﻿using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.CSharp;
using System.IO;
using System.Net;
using Selenium;
//using SeleniumTestSuiteRunner;
using ExcelLibrary;


namespace SeleniumOrderPathRunner {
    public class TestRunner {
        
        #region field variables
        StreamWriter logFile;
        ExcelLogger logExcel;

        AugmentedSelenium sel;//client connector that sends messages to the selenium server
        
        String logFileDirectoryPath;
        String serverURL;
        SeleniumServer.Browser browser;
        SeleniumServer.OrderAppEnvironment environment;

        Uri orderURI;//the template base url(http://order.rhapsody.com/ (prod), http://127.0.0.1:8080/signup-web/ (local), ) that should match the base URLS that come back from selenium
        Uri orderMarketingURI;
        Uri payflowURI;//the template base urls that should match the base URLS that come back from selenium
        Uri mp3StoreURI;
        Uri rotwURI;
        Uri rotwSigninFullURI;
        Uri mp3SigninFullURI;
        Uri mp3PurchaseFlowFullURI;
        Uri sessExpireFullURI;//necessary because this has no consistent structure currently

        TestCaseGroups[] testCaseWhiteList;
        String[] orderpathsWhiteList;

        OrderPathPage[] pageTypeTemplates;

        public delegate bool DifferedComparisonDelegate();

        public enum OrderPageTypes {
            Unrecognized = 0, SignIn, SignUp, DifferedOffer, Payflow, Receipt, TechDif, AlreadyMember, SessionExpired, TrialExpired, UpsellOffer, UnavailableMembership
        };
        public enum OrderPathSkin {
            Unknown=0, Sierra, S32rhapsodyMobile, S25vcast, Rhapsody2, Order2, S1rhapsody25, RhapRewardsSkin,
            RhapMP3CouponsSkin, RhapPrepaidDownloadSkin, S13rhapsody, Mp3StoreRhapsodySkin, Mp3StoreHPTouchSkin,
            RhapPrepaidSubscriptionSkin, S3rhapsodyInclient, Hptouch, S33rhapcom2, rhapCostcoRewardsSkin, rhapCostcoMP3CouponSkin,
            S13rhapsodyWithAmazon, napsterMyCokeRewardsMP3CouponSkin
        };
        public enum TestCaseGroups {
            AccountCreation, SubscriptionSignUp, SignIn, TrackPurchase, PopupLinks
        };
        /// <summary>
        /// This defines the logic flow of the orderpath. It is how validation is determined when 
        /// going from one page to another. See docs on http://musicwiki-corp-1101.sea1.rhapsody.com/index.php/Rhapsody_Online/Orderpath
        /// for details on orderpath flow types.
        /// </summary>
        public enum OrderPathFlow {A,B, E, F, G, J, K, M };  
        /// <summary>
        /// Sorted list of orderpath metadata including name, trial, url and so on.
        /// </summary>
        LinkedList<OrderPath> orderpaths;

        const String EXISTING_RHAP_ACCOUNTNAME = @"qa_seleniumNoSubAcc@rhapsody.lan";
        OrderPath R25PATH = new OrderPath();//best practice to make static or something?            

        public enum AgreementRequiredStates {California=0, Washington};

        //TODO flesh out credit card data enum (based on environment as well as for different users if possible)
        /*
         * MC 5212615245110125
         * AX 378654612031649
         * Discover 6011503531118021
         * Visa 4219829465271691
         * 4716087191483548
         * 4532166302145691
         * 4485581720174502
         * 4022956594110933
         * 4716465352659769
         * 4556391783361697
         * */

        #endregion



        /// <summary>
        /// Instantiates the TestRunner object.
        /// </summary>
        /// <param name="selDir">The local machine path to save the logging file</param>
        /// <param name="serverURL">The IP of the server running the selenium RC server</param>
        /// <param name="browser">Available browsers: *firefox, *mock, *firefoxproxy, *pifirefox,
        /// *chrome, *iexploreproxy, *iexplore, *firefox3, *safariproxy, *googlechrome, *konqueror,
        /// *firefox2, *safari, *piiexplore, *firefoxchrome, *opera, *iehta, *custom</param>
        /// <param name="environment">Testing environment. Currently, int and production are available.</param>
        public TestRunner(String logPath, String serverURL, SeleniumServer.Browser browser, SeleniumServer.OrderAppEnvironment environment, TestCaseGroups[] testCases, String[] orderpathNames) {
            this.logFileDirectoryPath = logPath;
            this.serverURL = serverURL;
            this.browser = browser;
            this.environment = environment;
            buildEnvironmentSpecificURIs(environment);
            buildOrderpathPageTemplates();
            buildStaticPaths();

            if (testCases.Length == 0) {
                Array enumArray = Enum.GetValues(typeof(TestCaseGroups));
                testCaseWhiteList = new TestCaseGroups[enumArray.GetLength(0)];
                for (int i = 0; i < testCaseWhiteList.Length; i++) {
                    testCaseWhiteList[i] = (TestCaseGroups)enumArray.GetValue(i);
                }
            } else {
                testCaseWhiteList = testCases;
            }
            orderpathsWhiteList = orderpathNames;
            Array.Sort<String>(orderpathsWhiteList);
        }




        /// <summary>
        /// This function runs, logs and closes all the tests. It is the main and only function to be called to run the automated tests.
        /// It starts the client connection to the selenium proxy server, which is already running.
        /// </summary>
        public void runTests() {
            //String test = logFileDirectoryPath + Path.DirectorySeparatorChar + "seleniumLog-" + DateTime.Now.ToString("yyyy'-'MM'-'dd'_'HH'-'mm'-'ss") + ".txt";
            logFile = new StreamWriter(logFileDirectoryPath + Path.DirectorySeparatorChar + "seleniumLog-" + DateTime.Now.ToString("yyyy'-'MM'-'dd'_'HH'-'mm'-'ss") + ".txt");
            logExcel = new ExcelLogger(logFileDirectoryPath, environment, browser);
            //no error handling for streamwriter path argument exceptions and IO exceptions, and path argumentExceptions
            logLine("Rhapsody Orderpath Test Execution Log");
            logLine("Browser: "+browser.ToString());
            logLine("Testing Environment: " + environment.ToString() + Environment.NewLine);
            sel = new AugmentedSelenium(new HttpCommandProcessor( serverURL, 4444, "*"+ browser.ToString().ToLower(), "http://www.rhapsody.com"));
            try {
                sel.Start();
                initializeBrowserConfig();
                runGetOrderPathFlows();
                //start threading here
                foreach (OrderPath o in orderpaths) {
                    LogBuffer logBuffer = new LogBuffer();

                    bool testWasRun = true;
                    try {
                        testWasRun = runOrderPathTests(o, ref logBuffer);
                    } catch (Exception ex) {
                        logLine(ref logBuffer, ex.Message);
                        logLine(ref logBuffer, "OrderPath " + o.Name + " failed to run" + Environment.NewLine);
                    } finally {
                        if (testWasRun) {
                            try {
                                sel.openBlankPage(browser);
                                tearDownTestCase(false, true, true);
                            } catch (Exception e) {
                                logLine(ref logBuffer, "ERROR: Orderpath cleanup failed. This may cause problems with subsequent tests");
                                logLine(ref logBuffer, e.Message + Environment.NewLine);
                            } finally {
                                //if test was not run, no logging to buffer occurs so this will catch all logic paths that log to buffer
                                logExcel.addTestResults(logBuffer);
                                logLine(logBuffer); 
                            }
                        }
                    }   
                }
                //rejoin threads here

            } catch (Exception e) {
                logLine(e.Message);
                logLine("Tests Failed" + Environment.NewLine);
            } finally {
                tearDownServerAndLogging();
            }
        }




        



        #region TADMIN ORDERPATH TESTS
        /// <summary>
        /// Opens the int or prod realstore.rhapsody.com/tadmin/marketing test page with all the 
        /// Orderpaths. It then ingests all the relevent table info for use later.
        /// </summary>
        private void runGetOrderPathFlows() {
            logLine("Getting all existing orderpath data");
            orderpaths = new LinkedList<OrderPath>(); 
            
            try {
                sel.Open(orderMarketingURI.AbsoluteUri);
                sel.WaitForPageToLoad("25000");
                System.Threading.Thread.Sleep(200);
                sel.assertPresentLocation(orderMarketingURI.AbsoluteUri);
            } catch (TestAssertionException te) {
                te.addLineToDataTop("opening marketing page failed");
                throw;
            }



            switch (environment) {
                case SeleniumServer.OrderAppEnvironment.Local:
                ingestMarketingData(new String[] { "coupons", "mp3store", "Rhapsody 25", "rhapsody premier", "rhapsody premier plus", "downloadcard", "prepaidcard" }, 5, 7, 8);
                break;

                case SeleniumServer.OrderAppEnvironment.Int:
                ingestMarketingData(new String[] { "rhapsody to go", "rhapsody", "rhapsody premier", "rhapsody premier plus", "rhapsody unlimited" }, 9, 11, 12);
                break;

                case SeleniumServer.OrderAppEnvironment.Load:
                ingestMarketingData(new String[] { "rhapsody to go", "rhapsody", "rhapsody premier", "rhapsody premier plus", "rhapsody unlimited" }, 9, 11, 12);
                break;

                case SeleniumServer.OrderAppEnvironment.Beta:
                //beta opens up the int-1203 tadmin page instead of /marketing(because there isn't one) so it has an extra sign in step
                try {
                    sel.Click(@"//input[@type='submit' and @value='login']");
                    sel.WaitForPageToLoad("25000");
                    sel.assertLocatorExistence(new String[] { @"//input[@type='submit' and @value='login']" }, AugmentedSelenium.Set.None);
                    sel.assertPresentLocation(orderMarketingURI.AbsoluteUri);
                }
                catch (SeleniumException se) {
                    throw new TestAssertionException("Signing in to marketing page failed", se);
                }
                catch (TestAssertionException te) {
                    te.addLineToDataTop("Signing in to marketing page failed");
                    throw;
                }  

                ingestMarketingData(new String[] { "rhapsody to go", "rhapsody", "rhapsody premier", "rhapsody premier plus", "rhapsody unlimited" }, 9, 11, 12);
                break;

                case SeleniumServer.OrderAppEnvironment.Test:
                ingestMarketingData(new String[] { "rhapsody to go", "rhapsody", "rhapsody premier", "rhapsody premier plus", "rhapsody unlimited" }, 9, 11, 12);
                break;

                case SeleniumServer.OrderAppEnvironment.Prod:

                break;
            }
            

            logLine("Successfully retrieved all " + orderpaths.Count + " orderpaths" + Environment.NewLine);
            sel.openBlankPage(browser);
        }





        /// <summary>
        /// Adds all Orderpaths listed in marketing page for sbuscription types specified
        /// The current list is for non local is 
        /// rhapsody unlimited
        /// rhapsody premier plus
        /// rhapsody premier
        /// rhapsody
        /// rhapsody to go
        /// 
        /// and local also contains 
        /// prepaidcard
        /// downloadcard
        /// mp3store
        /// coupons
        /// Rhapsody 25
        /// 
        /// 1.0 environments metadata columns
        /// trial 9
        /// skin 11
        /// active 12
        /// 
        /// 2.0 (local)
        /// trial 5
        /// skin 7
        /// active 8
        /// </summary>
        /// <param name="subscriptionTypes"></param>
        private void ingestMarketingData(String[] subscriptionTypes, int trial, int skin, int active) {
            foreach (String s in subscriptionTypes) {
                int row = 1;
                while (sel.IsElementPresent(@"//div[@id='url-"+s+@"']/table[1]/tbody[1]/tr[" + row + @"]")) {
                    logExcel.addOrderpathData(sel.GetText(@"//div[@id='url-" + s + @"']/table[1]/tbody[1]/tr[" + row + @"]/td[1]"),
                        sel.GetAttribute(@"//div[@id='url-" + s + @"']/table[1]/tbody[1]/tr[" + row + @"]/td[2]/a[1]@href"),
                        sel.GetText(@"//div[@id='url-" + s + @"']/table[1]/tbody[1]/tr[" + row + @"]/td["+skin+"]"));

                    OrderPath curOrderPath = new OrderPath();
                    curOrderPath.CategoryTab = "url-" + s ;
                    curOrderPath.Name = sel.GetText(@"//div[@id='url-" + s + @"']/table[1]/tbody[1]/tr[" + row + @"]/td[1]");
                    curOrderPath.URL = sel.GetAttribute(@"//div[@id='url-" + s + @"']/table[1]/tbody[1]/tr[" + row + @"]/td[2]/a[1]@href").Replace(@"/realstore",@"");
                    curOrderPath.Trial = Convert.ToBoolean(sel.GetText(@"//div[@id='url-" + s + @"']/table[1]/tbody[1]/tr[" + row + @"]/td[" + trial + "]"));
                    curOrderPath.Active = Convert.ToBoolean(sel.GetText(@"//div[@id='url-" + s + @"']/table[1]/tbody[1]/tr[" + row + @"]/td["+active+"]"));
                    curOrderPath.Skin = (OrderPathSkin)Enum.Parse(typeof(OrderPathSkin),
                        sel.GetText(@"//div[@id='url-" + s + @"']/table[1]/tbody[1]/tr[" + row + @"]/td["+skin+"]").Replace("-", ""),
                        true);
                    curOrderPath.Post = curOrderPath.Name.Contains("-auto");
                    curOrderPath.SignUpOverlay = curOrderPath.Name.Contains("-offerupsell-overlay");
                    orderpaths.AddLast(curOrderPath);
                    row++;
                }
            }
        }






        /// <summary>
        /// Runs a particular set of tests. These tests tend to be grouped together by purpose and 
        /// designed to be run subsequently in a more efficient manner than a random set of test. 
        /// The refresh behavior is custom tailored between each test in the group, and some tests
        /// themselves consider existing page location to determine how much resetting it needs to do.
        /// Test groups can be run in any order however, as the testing state is reset fully between suites.
        /// </summary>
        /// <param name="orderpath"></param>
        /// <param name="testGroup"></param>
        private void runOrderPathTestGroup(OrderPath orderpath, TestCaseGroups testGroup, ref LogBuffer lb) {
            switch(testGroup){
                case TestCaseGroups.AccountCreation:
                runOrderpathAccountCreationTests(orderpath, ref lb);
                break;
                case TestCaseGroups.PopupLinks:
                runOrderpathPopupTests(orderpath, ref lb);
                break;
                case TestCaseGroups.SignIn:
                runOrderpathSignInTests(orderpath, ref lb);
                break;
                case TestCaseGroups.SubscriptionSignUp:
                runOrderpathSubscriptionTests(orderpath, ref lb);
                break;
                case TestCaseGroups.TrackPurchase:
                runOrderpathTrackPurchaseTests(orderpath, ref lb);
                break;
            }
            try {
                sel.openBlankPage(browser);
                tearDownTestCase(false, true, true);
            } catch (Exception e) {
                logLine(ref lb, "ERROR: TestGroup cleanup failed. This may cause problems with subsequent tests");
                logLine(ref lb, e.Message + Environment.NewLine);
            }
        }


        /// <summary>
        /// Checks whether any string in the whitelist equals the orderpath name or 
        /// if any wildcard string in the white list is contained in the orderpath name
        /// </summary>
        /// <param name="orderpathName"></param>
        /// <param name="orderpathsWhiteList"></param>
        /// <returns></returns>
        private bool isPathNameInWhiteList(String orderpathName, String[] orderpathsWhiteList) {
            foreach(String s in orderpathsWhiteList) {
                if(s.EndsWith("*")) {
                    if( orderpathName.Contains(s.Substring(0, s.Length -1)) ){
                        return true;
                    }
                } else {
                    if(s.CompareTo(orderpathName)==0) {
                        return true;
                    }
                }
            }
            return false;

        }




        /// <summary>
        /// Runs all relevent tests for a single orderpath and logs the results.
        /// Each test is self contained and any bleed is controlled by how the 
        /// teardown of the test is done. Pages can be left open, cookies uncleared
        /// or not as specified at the end of each test.
        /// </summary>
        /// <param name="orderpath"></param>
        /// <returns></returns>
        private bool runOrderPathTests(OrderPath orderpath, ref LogBuffer lb) {
            if (!orderpath.Active) {
                return false;
            }

            if(orderpathsWhiteList.Length > 0 && !isPathNameInWhiteList(orderpath.Name, orderpathsWhiteList) ) {
                return false;//there is a white list and this orderpath is not in it
            }

            logLine(ref lb, "Orderpath: " + orderpath.Name);
            logLine(ref lb, "Location: " + orderpath.URL);
            logLine(ref lb, "Trial offer: " + orderpath.Trial);
            logLine(ref lb, "Skin: " + orderpath.Skin);

            foreach (TestCaseGroups testGroup in testCaseWhiteList) {
                runOrderPathTestGroup(orderpath, testGroup, ref lb);
            }

            return true;
        }





        #region test suites
        /// <summary>
        /// Runs a static list of account creation tests.
        /// </summary>
        /// <param name="path"></param>
        private void runOrderpathAccountCreationTests(OrderPath orderpath, ref LogBuffer lb) {
            try {
                createAccountValidCredentials(orderpath);
                logExcel.addTestResults(ref lb, orderpath, "create valid orderpath account", true);
                logLine(ref lb, "PASS: Sign up succeeded to username and password page" + Environment.NewLine);
            } catch (Exception e) {
                logExcel.addTestResults(ref lb, orderpath, "create valid orderpath account", false);
                logLine(ref lb, "FAIL: Test valid account creation failed: " + e.Message + Environment.NewLine);
            } finally {
                tearDownTestCase(true, true, true);//refresh since new acc is created it needs to be cleared, goes to safe page on success for refresh to avoid POST crap
            }
            try {
                createPostAccountValidCredentials(orderpath);
                logExcel.addTestResults(ref lb, orderpath, "create valid orderpath post account", true);
                logLine(ref lb, "PASS: Sign up succeeded to post" + Environment.NewLine);
            } catch (Exception e) {
                logExcel.addTestResults(ref lb, orderpath, "create valid orderpath post account", false);
                logLine(ref lb, "FAIL: Test valid post account creation failed: " + e.Message + Environment.NewLine);
            } finally {
                tearDownTestCase(false, true, true);//refresh since new acc is created it needs to be cleared, goes to safe page on success for refresh to avoid POST crap
            }
            try {
                testSignUpInvalidCredentialsBadCoupon(orderpath);
                logExcel.addTestResults(ref lb, orderpath, "invalid orderpath account - bad coupon", true);
                logLine(ref lb, "PASS: Sign up failed as expected for invalid coupon" + Environment.NewLine);
            } catch (Exception e) {
                logExcel.addTestResults(ref lb, orderpath, "invalid orderpath account - bad coupon", false);
                logLine(ref lb, "FAIL: Test valid account creation using invalid coupon failed: " + e.Message + Environment.NewLine);
            } finally {
                tearDownTestCase(false, false, false);
            }
            try {
                testSignUpInvalidCredentialsInvalidEmail(orderpath);
                logExcel.addTestResults(ref lb, orderpath, "invalid orderpath account - bad email", true);
                logLine(ref lb, "PASS: Sign up failed as expected with invalid email" + Environment.NewLine);
            } catch (Exception e) {
                logExcel.addTestResults(ref lb, orderpath, "invalid orderpath account - bad email", false);
                logLine(ref lb, "FAIL: Test invalid account creation using invalid email address failed: " + e.Message + Environment.NewLine);
            } finally {
                tearDownTestCase(false, false, false);
            }
            try {
                testSignUpInvalidCredentialsInvalidPassword(orderpath);
                logExcel.addTestResults(ref lb, orderpath, "invalid orderpath account - bad password", true);
                logLine(ref lb, "PASS: Sign up failed as expected with invalid password" + Environment.NewLine);
            } catch (Exception e) {
                logExcel.addTestResults(ref lb, orderpath, "invalid orderpath account - bad password", false);
                logLine(ref lb, "FAIL: Test invalid account creation with too short password failed: " + e.Message + Environment.NewLine);
            } finally {
                tearDownTestCase(false, false, false);
            }            
            try {
                testSignUpInvalidCredentialsMismatchPassword(orderpath);
                logExcel.addTestResults(ref lb, orderpath, "invalid orderpath account - passwords not identical", true);
                logLine(ref lb, "PASS: Sign up failed as expected with mismatching password and confirmation" + Environment.NewLine);
            } catch (Exception e) {
                logExcel.addTestResults(ref lb, orderpath, "invalid orderpath account - passwords not identical", false);
                logLine(ref lb, "FAIL: Test invalid account creation with mismatching password and confirmation failed: " + e.Message + Environment.NewLine);
            } finally {
                tearDownTestCase(false, false, false);
            }
            try {
                testSignUpInvalidCredentialsMissingConfirmation(orderpath);
                logExcel.addTestResults(ref lb, orderpath, "invalid orderpath account - missing repeated password", true);
                logLine(ref lb, "PASS: Sign up failed as expected with missing password confirmation" + Environment.NewLine);
            } catch (Exception e) {
                logExcel.addTestResults(ref lb, orderpath, "invalid orderpath account - missing repeated password", false);
                logLine(ref lb, "FAIL: Test invalid account creation with missing confirmation failed: " + e.Message + Environment.NewLine);
            } finally {
                tearDownTestCase(false, false, false);
            }
            try {
                testSignUpInvalidCredentialsMissingEmail(orderpath);
                logExcel.addTestResults(ref lb, orderpath, "invalid orderpath account - missing email", true);
                logLine(ref lb, "PASS: Sign up failed as expected with missing email" + Environment.NewLine);
            } catch (Exception e) {
                logExcel.addTestResults(ref lb, orderpath, "invalid orderpath account - missing email", false);
                logLine(ref lb, "FAIL: Test invalid account creation with missing email failed: " + e.Message + Environment.NewLine);
            } finally {
                tearDownTestCase(false, false, false);
            }
            try {
                testSignUpInvalidCredentialsMissingPassword(orderpath);
                logExcel.addTestResults(ref lb, orderpath, "invalid orderpath account - missing password", true);
                logLine(ref lb, "PASS: Sign up failed as expected with missing password" + Environment.NewLine);
            } catch (Exception e) {
                logExcel.addTestResults(ref lb, orderpath, "invalid orderpath account - missing password", false);
                logLine(ref lb, "FAIL: Test invalid account creation with missing password failed: " + e.Message + Environment.NewLine);
            } finally {
                tearDownTestCase(false, false, false);
            }
            try {
                testSignUpInvalidCredentialsExistingEmail(orderpath);
                logExcel.addTestResults(ref lb, orderpath, "invalid orderpath account - existing email", true);
                logLine(ref lb, "PASS: Sign up failed as expected with existing email" + Environment.NewLine);
            } catch (Exception e) {
                logExcel.addTestResults(ref lb, orderpath, "invalid orderpath account - existing email", false);
                logLine(ref lb, "FAIL: Test invalid account creation using existing credentials failed: " + e.Message + Environment.NewLine);
            } finally {
                tearDownTestCase(true, true, true);
            }
        }



        /// <summary>
        /// Runs a static list of popup tests.
        /// </summary>
        /// <param name="path"></param>
        private void runOrderpathPopupTests(OrderPath orderpath, ref LogBuffer lb) {
            try {
                checkOrderPathPageHasPopupLinks(orderpath);
                logExcel.addTestResults(ref lb, orderpath, "Check popup links", true);
                logLine(ref lb, "PASS: Popup links exist and work" + Environment.NewLine);
            } catch (Exception e) {
                logExcel.addTestResults(ref lb, orderpath, "Check popup links", false);
                logLine(ref lb, "FAIL: Test popup links failed: " + e.Message + Environment.NewLine);
            } finally {
                tearDownTestCase(false, false, false);
            }

        }



        /// <summary>
        /// Runs a static list of subscription tests.
        /// I have just added a VI card to Paymentech simulator
        /// VISA, 4556474670906442,
        /// Expiration = 03/13,
        /// response code = 100,(validates so it can be used over and over in INT)
        /// Address verification = I1(?)
        /// 
        /// Steps to re-enable the trial:
        /// 1. Log into the CS tool: http://csgw-test.real.com/cstool/index.html
        /// 2. Search for the account via the email address.
        /// 3. Click the "Enable Free Trial" link on the right. (See screenshot)
        /// 4. Click the "Clear Free Trial" button.
        /// 
        /// Additionally, if you're using this for automation I'm wondering if it would be good to remove the credit card from the account after the test has completed so it can clean-up after itself. To do this you'll need to:
        ///1. Log into the CS tool: http://csgw-test.real.com/cstool/index.html
        ///2. Search for the account via the email address.
        ///3. Cancel the contract by:
        ///3a. Clicking the contract name under the "Contracts" section on the right.
        ///3b. Click the "Cancel" button.
        ///3c. Click "OK" on the JS confirmation.
        ///4. Once that's done, you can remove the credit card by:
        ///4a. Returning to the account screen in step 2.
        ///4b. Click the "Payment Methods" link on the right.
        ///4c. Select the CC to delete (should already be selected if there's only one).
        ///4d. Click the "Delete Selected" button.

        /// </summary>
        /// <param name="orderpath"></param>
        private void runOrderpathSubscriptionTests(OrderPath orderpath, ref LogBuffer lb) {
            try {
                testPayflowInvalidCredentialsEverythingMissing(orderpath);
                logExcel.addTestResults(ref lb, orderpath, "Invalid orderpath subscription - missing everything", true);
                logLine(ref lb, "PASS: Test CC page no CC info" + Environment.NewLine);
            } catch (Exception e) {
                logExcel.addTestResults(ref lb, orderpath, "Invalid orderpath subscription - missing everything", false);
                logLine(ref lb, "FAIL: Test CC page no CC info did not fail as expected: " + e.Message + Environment.NewLine);
            } finally {
                tearDownTestCase(false, false, false);
            }
            try {
                testPayflowInvalidCredentialsOnlyName(orderpath);
                logExcel.addTestResults(ref lb, orderpath, "Invalid orderpath subscription - only name", true);
                logLine(ref lb, "PASS: Test CC page only name" + Environment.NewLine);
            } catch (Exception e) {
                logExcel.addTestResults(ref lb, orderpath, "Invalid orderpath subscription - only name", false);
                logLine(ref lb, "FAIL: Test CC page only name did not fail as expected: " + e.Message + Environment.NewLine);
            } finally {
                tearDownTestCase(false, false, false);
            }
            try {
                testPayflowInvalidCredentialsMissingCCType(orderpath);
                logExcel.addTestResults(ref lb, orderpath, "Invalid orderpath subscription - missing CC type", true);
                logLine(ref lb, "PASS: Test CC page missing CC type" + Environment.NewLine);
            } catch (Exception e) {
                logExcel.addTestResults(ref lb, orderpath, "Invalid orderpath subscription - missing CC type", false);
                logLine(ref lb, "FAIL: Test CC page missing CC type did not fail as expected: " + e.Message + Environment.NewLine);
            } finally {
                tearDownTestCase(false, false, false);
            }
            try {
                testPayflowInvalidCredentialsMissingState(orderpath);
                logExcel.addTestResults(ref lb, orderpath, "Invalid orderpath subscription - missing state", true);
                logLine(ref lb, "PASS: Test CC page missing state" + Environment.NewLine);
            } catch (Exception e) {
                logExcel.addTestResults(ref lb, orderpath, "Invalid orderpath subscription - missing state", false);
                logLine(ref lb, "FAIL: Test CC page missing state did not fail as expected: " + e.Message + Environment.NewLine);
            } finally {
                tearDownTestCase(false, false, false);
            }
            try {
                testPayflowInvalidCredentialsInvalidZip(orderpath);
                logExcel.addTestResults(ref lb, orderpath, "Invalid orderpath subscription - invalid zip", true);
                logLine(ref lb, "PASS: Test CC page invalid zip" + Environment.NewLine);
            } catch (Exception e) {
                logExcel.addTestResults(ref lb, orderpath, "Invalid orderpath subscription - invalid zip", false);
                logLine(ref lb, "FAIL: Test CC page invalid zip did not fail as expected: " + e.Message + Environment.NewLine);
            } finally {
                tearDownTestCase(false, false, false);
            }
            try {
                testPayflowInvalidCredentialsInvalidCCNumber(orderpath);
                logExcel.addTestResults(ref lb, orderpath, "Invalid orderpath subscription - invalid CC number", true);
                logLine(ref lb, "PASS: Test CC page invalid CC number" + Environment.NewLine);
            } catch (Exception e) {
                logExcel.addTestResults(ref lb, orderpath, "Invalid orderpath subscription - invalid CC number", false);
                logLine(ref lb, "FAIL: Test CC page invalid CC number did not fail as expected: " + e.Message + Environment.NewLine);
            } finally {
                tearDownTestCase(false, false, false);
            }
            try {
                testPayflowInvalidCredentialsExpiredCCDate(orderpath);
                logExcel.addTestResults(ref lb, orderpath, "Invalid orderpath subscription - invalid CC date", true);
                logLine(ref lb, "PASS: Test CC page expired CC date" + Environment.NewLine);
            } catch (Exception e) {
                logExcel.addTestResults(ref lb, orderpath, "Invalid orderpath subscription - invalid CC date", false);
                logLine(ref lb, "FAIL: Test CC page expired credit card date did not fail as expected: " + e.Message + Environment.NewLine);
            } finally {
                tearDownTestCase(false, false, false);
            }
            try {
                testPayflowInvalidCredentialsMissingSubscriptionTermsCheckbox(orderpath);
                logExcel.addTestResults(ref lb, orderpath, "Invalid orderpath subscription - missing legal terms checkbox", true);
                logLine(ref lb, "PASS: Test CC page legal terms fails without checking checkbox" + Environment.NewLine);
            } catch (Exception e) {
                logExcel.addTestResults(ref lb, orderpath, "Invalid orderpath subscription - missing legal terms checkbox", false);
                logLine(ref lb, "FAIL: Test CC page no check box for submit with legal terms required credentials did not fail as expected: " + e.Message + Environment.NewLine);
            } finally {
                tearDownTestCase(false, false, false);
            }
            try {
                createSubscriptionTrialExpired(orderpath);
                logExcel.addTestResults(ref lb, orderpath, "Create valid orderpath subscription - trial expired", true);
                logLine(ref lb, "PASS: Test subscription sign up using valid trial expired credit card information" + Environment.NewLine);
            } catch (Exception e) {
                logExcel.addTestResults(ref lb, orderpath, "Create valid orderpath subscription - trial expired", false);
                logLine(ref lb, "FAIL: Test valid trial expired credit card information failed: " + e.Message + Environment.NewLine);
            } finally {
                tearDownTestCase(false, true, false);
            }
            try {
                createSubscriptionTermsRequiredState(orderpath);
                logExcel.addTestResults(ref lb, orderpath, "Create valid orderpath subscription - terms required", true);
                logLine(ref lb, "PASS: Test subscription sign up using valid credit card information for terms required state" + Environment.NewLine);
            } catch (Exception e) {
                logExcel.addTestResults(ref lb, orderpath, "Create valid orderpath subscription - terms required", false);
                logLine(ref lb, "FAIL: Test subscription sign up using valid credit card information for terms required state failed: " + e.Message + Environment.NewLine );
            } finally {
                tearDownTestCase(false, true, false);
            }
            try {
                createSubscriptionTrialEligible(orderpath);
                logExcel.addTestResults(ref lb, orderpath, "Create valid orderpath subscription - trial eligible", true);
                logLine(ref lb, "PASS: Test subscription sign up using valid trial eligible credit card information" + Environment.NewLine);
            } catch (Exception e) {
                logExcel.addTestResults(ref lb, orderpath, "Create valid orderpath subscription - trial eligible", false);
                logLine(ref lb, "FAIL: Test valid trial eligible credit card information failed: " + e.Message + Environment.NewLine);
            } finally {
                tearDownTestCase(false, true, false);
            }
        }



        /// <summary>
        /// Runs a static list of track purchase tests.
        /// </summary>
        /// <param name="orderpath"></param>
        private void runOrderpathTrackPurchaseTests(OrderPath orderpath, ref LogBuffer lb) {
            /*
             * WHAT DOES IT MEAN TO TEST TRACK PURCHASE FOR A GIVEN ORDERPATH?
             * 
             * IT MEANS AN ACCOUNT TYPE CAN BE USED TO PURCHASE TRACKS. 
             * 
             * SHOULD ALL SUBSCRIPTION ACCOUNT TYPES CREATED VIA ORDERPATH BE
             * USEABLE FOR BUYING TRACKS?
             * 
             * IF THEY HAVE ENTERED CC INFO AND ALL THAT, THEN THEY SHOULD BE ABLE TO BUY A TRACK WITHOUT BEING SENT TO AN OP PAGE.
             * 
             * CREATE ACCOUNT THEN SUBSCRIPTION
             * IF DOES NOT GO THROUGH PAYFLOW PAGE AND INPUTS CC
             * THEN DEFAULT TO PASS SINCE NO ORDERPATH DOES NOT INCLUDE SUBSCRIPTION
             * ELSE, COMPLETE SUBSCRIPTION THEN TRY TO PURCHASE TRACK WITH THAT ACCOUNT
             * IF ASKED TO SUBSCRIBE(CC INFO) FAIL
             * IF TRACK NOT PURCHASED FAIL
             */ 
            try {
                buyOrderPathTrack(orderpath);
                logExcel.addTestResults(ref lb, orderpath, "Track purchase", true);
                logLine(ref lb, "PASS: Test buy track purchase" + Environment.NewLine);
            } catch (Exception e) {
                logExcel.addTestResults(ref lb, orderpath, "Track purchase", false);
                logLine(ref lb, "FAIL: Test buy track failed: " + e.Message + Environment.NewLine);
            } finally {
                tearDownTestCase(false, false, false);
            }
            
        }



        /// <summary>
        /// Runs a static list of sign in tests.
        /// </summary>
        /// <param name="orderpath"></param>
        private void runOrderpathSignInTests(OrderPath orderpath, ref  LogBuffer lb) {
            try {
                testSignInInvalidCredentialsNoPassword(orderpath);
                logExcel.addTestResults(ref lb, orderpath, "invalid sign in - no password", true);
                logLine(ref lb, "PASS: Invalid sign in with no password failed as expected" + Environment.NewLine);
            } catch (Exception e) {
                logExcel.addTestResults(ref lb, orderpath, "invalid sign in - no password", false);
                logLine(ref lb, "FAIL: Invalid sign in with no password  did not fail as expected: " + e.Message + Environment.NewLine);
            } finally {
                tearDownTestCase(false, false, false);
            }
            try {
                testSignInInvalidCredentialsWrongPassword(orderpath);
                logExcel.addTestResults(ref lb, orderpath, "invalid sign in - bad password", true);
                logLine(ref lb, "PASS: Invalid sign in with bad password failed as expected" + Environment.NewLine);
            } catch (Exception e) {
                logExcel.addTestResults(ref lb, orderpath, "invalid sign in - bad password", false);
                logLine(ref lb, "FAIL: Invalid sign in with bad password did not fail as expected: " + e.Message + Environment.NewLine);
            } finally {
                tearDownTestCase(false, false, false);
            }
            try {
                testSignInInvalidCredentialsNoEmail(orderpath);
                logExcel.addTestResults(ref lb, orderpath, "invalid sign in - no email", true);
                logLine(ref lb, "PASS: Invalid sign in with no email failed as expected" + Environment.NewLine);
            } catch(Exception e) {
                logExcel.addTestResults(ref lb, orderpath, "invalid sign in - no email", false);
                logLine(ref lb, "FAIL: Invalid sign in with no email did not fail as expected: " + e.Message + Environment.NewLine);
            } finally {
                tearDownTestCase(false, false, false);
            }
            try {
                testSignInInvalidCredentialsWrongEmailFormat(orderpath);
                logExcel.addTestResults(ref lb, orderpath, "invalid sign in - bad email format", true);
                logLine(ref lb, "PASS: Invalid sign in with bad email format failed as expected" + Environment.NewLine);
            } catch(Exception e) {
                logExcel.addTestResults(ref lb, orderpath, "invalid sign in - bad email format", false);
                logLine(ref lb, "FAIL: Invalid sign in with bad email format did not fail as expected: " + e.Message + Environment.NewLine);
            } finally {
                tearDownTestCase(false, false, false);
            }

            try {
                testSignInInvalidCredentialsNonexistingUser(orderpath);
                logExcel.addTestResults(ref lb, orderpath, "Invalid sign in - nonexisting account", true);
                logLine(ref lb, "PASS: Invalid sign in with nonexisting user failed as expected" + Environment.NewLine);
            } catch(Exception e) {
                logExcel.addTestResults(ref lb, orderpath, "Invalid sign in - nonexisting account", false);
                logLine(ref lb, "FAIL: Invalid sign in with nonexisting account did not fail as expected: " + e.Message + Environment.NewLine);
            } finally {
                tearDownTestCase(false, false, false);
            }
            try {
                testSignInValidCredentialsExistingUser(orderpath);
                logExcel.addTestResults(ref lb, orderpath, "Sign in with valid account", true);
                logLine(ref lb, "PASS: Test valid sign in with existing user" + Environment.NewLine);
            } catch (Exception e) {
                logExcel.addTestResults(ref lb, orderpath, "Sign in with valid account", false);
                logLine(ref lb, "FAIL: Test valid sign in failed: " + e.Message + Environment.NewLine);
            } finally {
                tearDownTestCase(false, true, false);
            }


        }
        #endregion






        #region account creation tests
        /// <summary>
        /// Creates a valid orderpath account. Tries handling all variations as well as those Orderpaths that default to sign in rather than sign up.
        /// Also attempts to POST for those orderpaths that support skipping sign up page.
        /// </summary>
        /// <param name="path"></param>
        private void createAccountValidCredentials(OrderPath path) {
            String email = "qa_" + System.DateTime.Now.ToString("ss.mm.HH_dd.MM.yyyy") + @"@rhapsody.lan";
            sel.openPage( path.URL, true, true );
            //String username;//email or username depending on path
            inputOrderPathAccount(email, "password", "password", getCouponType(path), path, out email);
            
            sel.assertLocatorText(new String[] { @"//p[@class='warning']" }, AugmentedSelenium.Set.All, AugmentedSelenium.Compare.HasNot, new String[] { @"Please correct the error(s) listed below and resubmit your form:" });

            assertSignInOnROTW(email, "password");
            
        }


        /// <summary>
        /// Tests positive account creation using POST for those paths that permit POSTs to skip sign up.
        /// It gets parameter set from looking at the sign up page(for username and coupon).
        /// </summary>
        /// <param name="path"></param>
        private void createPostAccountValidCredentials(OrderPath path) {
            if (!path.Post) {
                return;
            }
            //have to first open the path the regular way to check which parameters it accepts
            sel.openPage( path.URL, true, true );
            OrderPageTypes curPage = waitForPageType(path, new OrderPageTypes[] { OrderPageTypes.SignUp, OrderPageTypes.SignIn }, 1000, 200);
            if (curPage == OrderPageTypes.SignIn) {
                if (sel.IsElementPresent(@"//input[@id='newUserType']")) {
                    sel.Click(@"//input[@id='newUserType']");
                }
                curPage = waitForPageType(path, new OrderPageTypes[] { OrderPageTypes.SignUp }, 1000, 200);
            }
            assertCurrentPageIsExpectedType(curPage, new OrderPageTypes[] { OrderPageTypes.SignUp });

            List<KeyValuePair<string, string>> postParams = new List<KeyValuePair<string, string>>();
            String email = "qa_" + System.DateTime.Now.ToString("ss.mm.HH_dd.MM.yyyy") + @"@rhapsody.lan";
            postParams.Add(new KeyValuePair<string, string>("email", email));
            postParams.Add(new KeyValuePair<string, string>("password", "password"));
            postParams.Add( new KeyValuePair<string, string>( "confirmPassword", "password" ) );
            //username
            if ( sel.isLocatorExistence( pageTypeTemplates[(int)( OrderPageTypes.SignUp )].RuleValues[7][0], AugmentedSelenium.Set.AllSome ) ) {
                int cutoff = Math.Max(0, Math.Min(20, email.IndexOf("@")));
                postParams.Add(new KeyValuePair<string, string>("userNameNew", email.Substring(0, cutoff).Replace(".", "_")));   
            }
            //coupon
            if(sel.isLocatorExistence( pageTypeTemplates[(int)(OrderPageTypes.SignUp)].RuleValues[6][0], AugmentedSelenium.Set.AllSome)){
                postParams.Add(new KeyValuePair<string, string>("couponCode", getCouponType(path)));
            }
            
            sel.openPost(path.URL, postParams);
            sel.assertPresentLocation( payflowURI.AbsoluteUri, true );
        }



        private void testSignUpInvalidCredentialsBadCoupon(OrderPath path) {
            if(path.Skin != OrderPathSkin.RhapPrepaidSubscriptionSkin && path.Skin != OrderPathSkin.RhapRewardsSkin && path.Skin != OrderPathSkin.RhapPrepaidDownloadSkin && path.Skin != OrderPathSkin.RhapMP3CouponsSkin){
                return;
            }
            sel.openPage( path.URL, false, true );
            String email = "qa_" + System.DateTime.Now.ToString("ss.mm.HH_dd.MM.yyyy") + @"@rhapsody.lan";
            inputOrderPathAccount(email, "password", "password", "badCoupon", path, out email);
            sel.assertPresentLocation( path, true );
            sel.waitForLocatorExistence(new String[] { @"//div[@id='loginPageErrorsText']" }, AugmentedSelenium.Set.All, 25000, 200);  
            sel.assertLocatorExistence(new String[] { @"//div[@id='loginPageErrorsText']" }, AugmentedSelenium.Set.All);
            sel.assertLocatorText(new String[] { @"//p[@class='warning']" }, AugmentedSelenium.Set.All, AugmentedSelenium.Compare.Has, new String[] { @"Please correct the error(s) listed below and resubmit your form:" });
        }

        private void testSignUpInvalidCredentialsMissingPassword(OrderPath path) {
            sel.openPage( path.URL, false, true );
            String email = "qa_" + System.DateTime.Now.ToString("ss.mm.HH_dd.MM.yyyy") + @"@rhapsody.lan";
            inputOrderPathAccount(email, "", "", getCouponType(path), path, out email);
            sel.assertPresentLocation( path, true );
            sel.waitForLocatorExistence(new String[] { @"//div[@id='loginPageErrorsText']" }, AugmentedSelenium.Set.All, 25000, 200);  //sel.tryWaitForElementToExist(@"//div[@id='loginPageErrorsText']", 25000, 200);
            sel.assertLocatorExistence(new String[] { @"//div[@id='loginPageErrorsText']" }, AugmentedSelenium.Set.All);//sel.assertElementExists(@"//div[@id='loginPageErrorsText']");
            sel.assertLocatorText(new String[] { @"//p[@class='warning']" }, AugmentedSelenium.Set.All, AugmentedSelenium.Compare.Has, new String[] { @"Please correct the error(s) listed below and resubmit your form:" });//sel.assertTextForElementHasValue(@"//p[@class='warning']", @"Please correct the error(s) listed below and resubmit your form:");
        }

        private void testSignUpInvalidCredentialsMissingConfirmation(OrderPath path) {
            sel.openPage( path.URL, false, true );
            String email = "qa_" + System.DateTime.Now.ToString("ss.mm.HH_dd.MM.yyyy") + @"@rhapsody.lan";
            inputOrderPathAccount(email, "password", "", getCouponType(path), path, out email);
            sel.assertPresentLocation( path, true );
            sel.waitForLocatorExistence(new String[] { @"//div[@id='loginPageErrorsText']" }, AugmentedSelenium.Set.All, 25000, 200); //sel.tryWaitForElementToExist(@"//div[@id='loginPageErrorsText']", 25000, 200);
            sel.assertLocatorExistence(new String[] { @"//div[@id='loginPageErrorsText']" }, AugmentedSelenium.Set.All);//sel.assertElementExists(@"//div[@id='loginPageErrorsText']");
            sel.assertLocatorText(new String[] { @"//p[@class='warning']" }, AugmentedSelenium.Set.All, AugmentedSelenium.Compare.Has, new String[] { @"Please correct the error(s) listed below and resubmit your form:" });//sel.assertTextForElementHasValue(@"//p[@class='warning']", @"Please correct the error(s) listed below and resubmit your form:");
        }

        private void testSignUpInvalidCredentialsMissingEmail(OrderPath path) {
            sel.openPage( path.URL, false, true );
            String username;
            inputOrderPathAccount("", "password", "password", getCouponType(path), path, out username);
            sel.assertPresentLocation( path, true );
            sel.waitForLocatorExistence(new String[] { @"//div[@id='loginPageErrorsText']" }, AugmentedSelenium.Set.All, 25000, 200); //sel.tryWaitForElementToExist(@"//div[@id='loginPageErrorsText']", 25000, 200);
            sel.assertLocatorExistence(new String[] { @"//div[@id='loginPageErrorsText']" }, AugmentedSelenium.Set.All);//sel.assertElementExists(@"//div[@id='loginPageErrorsText']");
            sel.assertLocatorText(new String[] { @"//p[@class='warning']" }, AugmentedSelenium.Set.All, AugmentedSelenium.Compare.Has, new String[] { @"Please correct the error(s) listed below and resubmit your form:" });//sel.assertTextForElementHasValue(@"//p[@class='warning']", @"Please correct the error(s) listed below and resubmit your form:");
        }

        private void testSignUpInvalidCredentialsExistingEmail(OrderPath path) {
            sel.openPage( path.URL, false, true );
            String username;
            inputOrderPathAccount(TestRunner.EXISTING_RHAP_ACCOUNTNAME, "password", "password", getCouponType(path), path, out username);
            sel.assertPresentLocation( path, true );
            sel.waitForLocatorExistence(new String[] { @"//div[@id='loginPageErrorsText']" }, AugmentedSelenium.Set.All, 25000, 200); //sel.tryWaitForElementToExist(@"//div[@id='loginPageErrorsText']", 25000, 200);
            sel.assertLocatorExistence(new String[] { @"//div[@id='loginPageErrorsText']" }, AugmentedSelenium.Set.All);//sel.assertElementExists(@"//div[@id='loginPageErrorsText']");
            sel.assertLocatorText(new String[] { @"//p[@class='warning']" }, AugmentedSelenium.Set.AllSome, AugmentedSelenium.Compare.Has, new String[] { 
                EXISTING_RHAP_ACCOUNTNAME+@" already has an account with Rhapsody.", EXISTING_RHAP_ACCOUNTNAME.Replace(@"@rhapsody.lan","")+@" already has an account with Rhapsody." });
        }

        private void testSignUpInvalidCredentialsInvalidEmail(OrderPath path) {
            sel.openPage( path.URL, false, true );
            String username;
            inputOrderPathAccount("asdfghj", "password", "password", getCouponType(path), path, out username);
            sel.assertPresentLocation( path, true );
            sel.waitForLocatorExistence(new String[] { @"//div[@id='loginPageErrorsText']" }, AugmentedSelenium.Set.All, 25000, 200); //sel.tryWaitForElementToExist(@"//div[@id='loginPageErrorsText']", 25000, 200);
            sel.assertLocatorExistence(new String[] { @"//div[@id='loginPageErrorsText']" }, AugmentedSelenium.Set.All);//sel.assertElementExists(@"//div[@id='loginPageErrorsText']");
            sel.assertLocatorText(new String[] { @"//p[@class='warning']" }, AugmentedSelenium.Set.All, AugmentedSelenium.Compare.Has, new String[] { @"Please correct the error(s) listed below and resubmit your form:" });//sel.assertTextForElementHasValue(@"//p[@class='warning']", @"Please correct the error(s) listed below and resubmit your form:");
        }

        private void testSignUpInvalidCredentialsMismatchPassword(OrderPath path) {
            sel.openPage( path.URL, false, true );
            String email = "qa_" + System.DateTime.Now.ToString("ss.mm.HH_dd.MM.yyyy") + @"@rhapsody.lan";
            inputOrderPathAccount(email, "password", "asdfghj", getCouponType(path), path, out email);
            sel.assertPresentLocation( path, true );
            sel.waitForLocatorExistence(new String[] { @"//div[@id='loginPageErrorsText']" }, AugmentedSelenium.Set.All, 25000, 200); //sel.tryWaitForElementToExist(@"//div[@id='loginPageErrorsText']", 25000, 200);
            sel.assertLocatorExistence(new String[] { @"//div[@id='loginPageErrorsText']" }, AugmentedSelenium.Set.All);//sel.assertElementExists(@"//div[@id='loginPageErrorsText']");
            sel.assertLocatorText(new String[] { @"//p[@class='warning']" }, AugmentedSelenium.Set.All, AugmentedSelenium.Compare.Has, new String[] { @"Please correct the error(s) listed below and resubmit your form:" });//sel.assertTextForElementHasValue(@"//p[@class='warning']", @"Please correct the error(s) listed below and resubmit your form:");
        }


        private void testSignUpInvalidCredentialsInvalidPassword(OrderPath path) {
            sel.openPage( path.URL, false, true );
            String email = "qa_" + System.DateTime.Now.ToString("ss.mm.HH_dd.MM.yyyy") + @"@rhapsody.lan";
            inputOrderPathAccount(email, "1", "1", getCouponType(path), path, out email);
            sel.assertPresentLocation( path, true );
            sel.waitForLocatorExistence(new String[] { @"//div[@id='loginPageErrorsText']" }, AugmentedSelenium.Set.All, 25000, 200); //sel.tryWaitForElementToExist(@"//div[@id='loginPageErrorsText']", 25000, 200);
            sel.assertLocatorExistence(new String[] { @"//div[@id='loginPageErrorsText']" }, AugmentedSelenium.Set.All);//sel.assertElementExists(@"//div[@id='loginPageErrorsText']");
            sel.assertLocatorText(new String[] { @"//p[@class='warning']" }, AugmentedSelenium.Set.All, AugmentedSelenium.Compare.Has, new String[] { @"Please correct the error(s) listed below and resubmit your form:" });//sel.assertTextForElementHasValue(@"//p[@class='warning']", @"Please correct the error(s) listed below and resubmit your form:");
        }
        #endregion






        #region subscription payflow tests
        /// <summary>
        /// Creates a new account, and follows whatever flow is presented to it.
        /// Some metadata is used to demand certain features of the orderpath flow,
        /// but some logic will tolerate whatever manner of orderpath subscription flow
        /// it encounters. Only those features that seem strictly patterned by the 
        /// metadata is enforced. Messaging, intermediate flow pages and the like that
        /// have no obvious patterns or rules are assumed to be intentional when found.
        /// This may allow Orderpaths to pass incorrectly with wrong user experience, 
        /// but it will never pass an obviously broken orderpath. (negative tests check to 
        /// ensure bad user input results in failure to subscribe)
        /// </summary>
        /// <param name="path"></param>
        private void createSubscriptionTrialExpired(OrderPath path) {
            sel.openPage( path.URL, true, true );
            String email = "qa_" + System.DateTime.Now.ToString("ss.mm.HH_dd.MM.yyyy") + @"@rhapsody.lan";
            bool isCouponPath = !getCouponType(path).Equals("");
            inputOrderPathAccount(email, "password", "password", getCouponType(path), path, out email);
            
            OrderPageTypes curPageType = waitForPageType(path, new OrderPageTypes[] { 
                OrderPageTypes.Payflow, OrderPageTypes.Receipt, OrderPageTypes.DifferedOffer, OrderPageTypes.AlreadyMember, OrderPageTypes.SessionExpired,
                OrderPageTypes.TechDif, OrderPageTypes.SignIn, OrderPageTypes.SignUp, OrderPageTypes.UpsellOffer, OrderPageTypes.TrialExpired }, 1000, 200);

            //check for intermediate page
            if (curPageType == OrderPageTypes.DifferedOffer) {
                sel.SubmitForm( pageTypeTemplates[(int)(OrderPageTypes.DifferedOffer)].RuleValues[0][0][0] );
                sel.WaitForPageToLoad("25000");
                //have to wait for page to load at least a little bit, so that differed offer isn't picked up again before page changes
                curPageType = waitForPageType(path, new OrderPageTypes[] { 
                    OrderPageTypes.Payflow, OrderPageTypes.Receipt, OrderPageTypes.DifferedOffer, OrderPageTypes.AlreadyMember, OrderPageTypes.SessionExpired,
                    OrderPageTypes.TechDif, OrderPageTypes.SignIn, OrderPageTypes.SignUp, OrderPageTypes.UpsellOffer, OrderPageTypes.TrialExpired }, 1000, 200);
            }

            //check for early no cc completion page
            if (curPageType == OrderPageTypes.Receipt) {
                assertReceiptPageMessaging(isCouponPath, true, true);
                return;
            }
            
            //on CC page or failed through from above, either way assert on CC page and go through it to completion
            if (!isProductionSubscriptionEnvironement(environment)) {
                inputCCInfo("fName", "lName", true, "Visa", "4111111111111111", true, "12", true, "2024", "1234567890", "Timbuktu", "Seattle", true, "Oregon", "97007", false);
            } else {
                //CC INFO FOR OTHER ENVIRONMENTS?
            }

            if (path.Trial) {
                curPageType = waitForPageType(path, new OrderPageTypes[] {OrderPageTypes.TrialExpired, OrderPageTypes.SessionExpired, OrderPageTypes.TechDif }, 1000, 200);
                assertCurrentPageIsExpectedType(curPageType, new OrderPageTypes[] { OrderPageTypes.TrialExpired });

                sel.Click(sel.getFirstExistingElement(new String[] { @"//input[@id='continueButton']", @"//input[@id='startDownload']" }));
                sel.WaitForPageToLoad("25000");

                curPageType = waitForPageType(path, new OrderPageTypes[] { OrderPageTypes.Receipt, OrderPageTypes.Payflow, OrderPageTypes.UpsellOffer, OrderPageTypes.SessionExpired, OrderPageTypes.TechDif }, 1000, 200);

                if ( curPageType == OrderPageTypes.UpsellOffer) {//handle possible upsell offer
                    sel.Click(@"//a[@id='getRhapOnly']");
                    sel.WaitForPageToLoad("25000");
                    curPageType = waitForPageType(path, new OrderPageTypes[] { OrderPageTypes.Receipt, OrderPageTypes.SessionExpired, OrderPageTypes.TechDif }, 1000, 200);
                }
                    //must be on receipt page now or something broke
                assertCurrentPageIsExpectedType(curPageType, new OrderPageTypes[] { OrderPageTypes.Receipt });

                assertReceiptPageMessaging(isCouponPath, false, false);

            } else {
                curPageType = waitForPageType(path, new OrderPageTypes[] { OrderPageTypes.Receipt, OrderPageTypes.UpsellOffer, OrderPageTypes.TrialExpired, OrderPageTypes.SessionExpired, OrderPageTypes.TechDif }, 1000, 200);

                if (curPageType == OrderPageTypes.UpsellOffer) {//handle possible upsell offer
                    sel.Click(@"//a[@id='getRhapOnly']");
                    sel.WaitForPageToLoad("25000");
                    curPageType = waitForPageType(path, new OrderPageTypes[] { OrderPageTypes.Receipt, OrderPageTypes.TrialExpired, OrderPageTypes.SessionExpired, OrderPageTypes.TechDif }, 1000, 200);
                }

                assertCurrentPageIsExpectedType(curPageType, new OrderPageTypes[] { OrderPageTypes.Receipt });
                //Failure to find anything results in an exception that locator "" is not found. Might want to rework this to explain none of the expected locators exist
                assertReceiptPageMessaging(isCouponPath, false, false);
            }
        }




        private void createSubscriptionTermsRequiredState(OrderPath path) {
            sel.openPage(path.URL, true, true);
            String email = "qa_" + System.DateTime.Now.ToString("ss.mm.HH_dd.MM.yyyy") + @"@rhapsody.lan";
            bool isCouponPath = !getCouponType(path).Equals("");
            inputOrderPathAccount(email, "password", "password", getCouponType(path), path, out email);

            OrderPageTypes curPageType = waitForPageType(path, new OrderPageTypes[] { 
                OrderPageTypes.Payflow, OrderPageTypes.Receipt, OrderPageTypes.DifferedOffer, OrderPageTypes.AlreadyMember, OrderPageTypes.SessionExpired,
                OrderPageTypes.TechDif, OrderPageTypes.SignIn, OrderPageTypes.SignUp, OrderPageTypes.UpsellOffer, OrderPageTypes.TrialExpired }, 1000, 200);

            //check for intermediate page
            if(curPageType == OrderPageTypes.DifferedOffer) {
                sel.SubmitForm(pageTypeTemplates[(int)(OrderPageTypes.DifferedOffer)].RuleValues[0][0][0]);
                sel.WaitForPageToLoad("25000");
                //have to wait for page to load at least a little bit, so that differed offer isn't picked up again before page changes
                curPageType = waitForPageType(path, new OrderPageTypes[] { 
                    OrderPageTypes.Payflow, OrderPageTypes.Receipt, OrderPageTypes.DifferedOffer, OrderPageTypes.AlreadyMember, OrderPageTypes.SessionExpired,
                    OrderPageTypes.TechDif, OrderPageTypes.SignIn, OrderPageTypes.SignUp, OrderPageTypes.UpsellOffer, OrderPageTypes.TrialExpired }, 1000, 200);
            }

            //check for early no cc completion page
            if(curPageType == OrderPageTypes.Receipt) {
                assertReceiptPageMessaging(isCouponPath, true, true);
                return;
            }

            //on CC page or failed through from above, either way assert on CC page and go through it to completion
            if(!isProductionSubscriptionEnvironement(environment)) {
                inputCCInfo("fName", "lName", true, "Visa", "4111111111111111", true, "12", true, "2024", "1234567890", "Timbuktu", "Seattle", true, AgreementRequiredStates.Washington.ToString(), "98103", true);
            } else {
                //CC INFO FOR OTHER ENVIRONMENTS?
            }

            if(path.Trial) {
                curPageType = waitForPageType(path, new OrderPageTypes[] { OrderPageTypes.TrialExpired, OrderPageTypes.SessionExpired, OrderPageTypes.TechDif }, 1000, 200);
                assertCurrentPageIsExpectedType(curPageType, new OrderPageTypes[] { OrderPageTypes.TrialExpired });

                sel.Click(sel.getFirstExistingElement(new String[] { @"//input[@id='continueButton']", @"//input[@id='startDownload']" }));
                sel.WaitForPageToLoad("25000");

                curPageType = waitForPageType(path, new OrderPageTypes[] { OrderPageTypes.Receipt, OrderPageTypes.Payflow, OrderPageTypes.UpsellOffer, OrderPageTypes.SessionExpired, OrderPageTypes.TechDif }, 1000, 200);

                if(curPageType == OrderPageTypes.UpsellOffer) {//handle possible upsell offer
                    sel.Click(@"//a[@id='getRhapOnly']");
                    sel.WaitForPageToLoad("25000");
                    curPageType = waitForPageType(path, new OrderPageTypes[] { OrderPageTypes.Receipt, OrderPageTypes.SessionExpired, OrderPageTypes.TechDif }, 1000, 200);
                }
                //must be on receipt page now or something broke
                assertCurrentPageIsExpectedType(curPageType, new OrderPageTypes[] { OrderPageTypes.Receipt });

                assertReceiptPageMessaging(isCouponPath, false, false);

            } else {
                curPageType = waitForPageType(path, new OrderPageTypes[] { OrderPageTypes.Receipt, OrderPageTypes.UpsellOffer, OrderPageTypes.TrialExpired, OrderPageTypes.SessionExpired, OrderPageTypes.TechDif }, 1000, 200);

                if(curPageType == OrderPageTypes.UpsellOffer) {//handle possible upsell offer
                    sel.Click(@"//a[@id='getRhapOnly']");
                    sel.WaitForPageToLoad("25000");
                    curPageType = waitForPageType(path, new OrderPageTypes[] { OrderPageTypes.Receipt, OrderPageTypes.TrialExpired, OrderPageTypes.SessionExpired, OrderPageTypes.TechDif }, 1000, 200);
                }

                assertCurrentPageIsExpectedType(curPageType, new OrderPageTypes[] { OrderPageTypes.Receipt });
                //Failure to find anything results in an exception that locator "" is not found. Might want to rework this to explain none of the expected locators exist
                assertReceiptPageMessaging(isCouponPath, false, false);
            }
        }




        private void createSubscriptionTrialEligible(OrderPath path){
            renewCC();

            sel.openPage( path.URL, true, true );
            String email = "qa_" + System.DateTime.Now.ToString("ss.mm.HH_dd.MM.yyyy") + @"@rhapsody.lan";
            bool isCouponPath = !getCouponType(path).Equals("");
            inputOrderPathAccount(email, "password", "password", getCouponType(path), path, out email);

            OrderPageTypes curPageType = waitForPageType(path, new OrderPageTypes[] { 
                OrderPageTypes.Payflow, OrderPageTypes.Receipt, OrderPageTypes.DifferedOffer, OrderPageTypes.AlreadyMember, OrderPageTypes.SessionExpired,
                OrderPageTypes.TechDif, OrderPageTypes.SignIn, OrderPageTypes.SignUp, OrderPageTypes.UpsellOffer, OrderPageTypes.TrialExpired }, 1000, 200);

            //check for intermediate page
            if (curPageType == OrderPageTypes.DifferedOffer) {
                sel.SubmitForm( pageTypeTemplates[(int)(OrderPageTypes.DifferedOffer)].RuleValues[0][0][0] );
                sel.WaitForPageToLoad("25000");
                //have to wait for page to load at least a little bit, so that differed offer isn't picked up again before page changes
                curPageType = waitForPageType(path, new OrderPageTypes[] { 
                    OrderPageTypes.Payflow, OrderPageTypes.Receipt, OrderPageTypes.DifferedOffer, OrderPageTypes.AlreadyMember, OrderPageTypes.SessionExpired,
                    OrderPageTypes.TechDif, OrderPageTypes.SignIn, OrderPageTypes.SignUp, OrderPageTypes.UpsellOffer, OrderPageTypes.TrialExpired }, 1000, 200);
            }

            //check for early no cc completion page
            if (curPageType == OrderPageTypes.Receipt) {
                assertReceiptPageMessaging(isCouponPath, true, true);
                return;
            }
            
            //on CC page or failed through from above, either way assert on CC page and go through it to completion
            if (!isProductionSubscriptionEnvironement(environment)) {
                inputCCInfo("fName", "lName", true, "Visa", "4556474670906442", true, "12", true, "2024", "1234567890", "Timbuktu", "Seattle", true, "Oregon", "97007", false);
            } else {
                //CC INFO FOR OTHER ENVIRONMENTS?
            }

            if (path.Trial) {
                curPageType = waitForPageType(path, new OrderPageTypes[] {OrderPageTypes.Receipt, OrderPageTypes.UpsellOffer, OrderPageTypes.TrialExpired, OrderPageTypes.SessionExpired, OrderPageTypes.TechDif }, 1000, 200);

                if (curPageType == OrderPageTypes.UpsellOffer) {//handle possible upsell offer
                    sel.Click(@"//a[@id='getRhapOnly']");
                    sel.WaitForPageToLoad("25000");
                    curPageType = waitForPageType(path, new OrderPageTypes[] { OrderPageTypes.Receipt, OrderPageTypes.SessionExpired, OrderPageTypes.TechDif }, 1000, 200);
                }
                    
                //must be on receipt page now or something broke
                assertCurrentPageIsExpectedType(curPageType, new OrderPageTypes[] { OrderPageTypes.Receipt });
                assertReceiptPageMessaging(isCouponPath, true, false);
            } else {
                curPageType = waitForPageType(path, new OrderPageTypes[] { OrderPageTypes.Receipt, OrderPageTypes.UpsellOffer, OrderPageTypes.TrialExpired, OrderPageTypes.SessionExpired, OrderPageTypes.TechDif }, 1000, 200);

                if (curPageType == OrderPageTypes.UpsellOffer) {//handle possible upsell offer
                    sel.Click(@"//a[@id='getRhapOnly']");
                    sel.WaitForPageToLoad("25000");
                    curPageType = waitForPageType(path, new OrderPageTypes[] { OrderPageTypes.Receipt, OrderPageTypes.TrialExpired, OrderPageTypes.SessionExpired, OrderPageTypes.TechDif }, 1000, 200);
                }

                assertCurrentPageIsExpectedType(curPageType, new OrderPageTypes[] { OrderPageTypes.Receipt });
                //Failure to find anything results in an exception that locator "" is not found. Might want to rework this to explain none of the expected locators exist
                assertReceiptPageMessaging(isCouponPath, false, false);
            }
        }



        
        /// <summary>
        /// Navigates to payflow page with new account unless this orderpath is already on payflow page. If it finds payflow page,
        /// submits bad data and asserts error messaging response. If no payflow page exists and flow instead goes directly to
        /// success page, the test defaults to passed. If other bad pages are detected, then the test fails.
        /// </summary>
        /// <param name="path"></param>
        private void testPayflowInvalidCredentialsEverythingMissing(OrderPath path) {
            //test if already on payflow page for this orderpath. Cannot be from another path since test state is cleared between each path
            if (!isCurrentPageSpecifiedType(sel.GetLocation(), OrderPageTypes.Payflow, path)) {
                sel.openPage( path.URL, true, true );
                String email = "qa_" + System.DateTime.Now.ToString("ss.mm.HH_dd.MM.yyyy") + @"@rhapsody.lan";
                inputOrderPathAccount(email, "password", "password", getCouponType(path), path, out email);
                OrderPageTypes curPageType = waitForPageType(path, new OrderPageTypes[] { OrderPageTypes.Payflow, OrderPageTypes.DifferedOffer, OrderPageTypes.Receipt, OrderPageTypes.TechDif, OrderPageTypes.SessionExpired }, 25000, 250);
                if (curPageType == OrderPageTypes.DifferedOffer) {//check for intermediate page
                    sel.SubmitForm( pageTypeTemplates[(int)(OrderPageTypes.DifferedOffer)].RuleValues[0][0][0] );
                    curPageType = waitForPageType(path, new OrderPageTypes[] { OrderPageTypes.Payflow, OrderPageTypes.Receipt, OrderPageTypes.TechDif, OrderPageTypes.SessionExpired }, 25000, 250);
                }
                if (curPageType == OrderPageTypes.Receipt) {
                    return;
                } else if (curPageType != OrderPageTypes.Payflow) {//at this point, can only validly be payflow
                    throw new TestAssertionException("Could not reach payflow page. Instead on " + curPageType.ToString());
                }
            }
            //on CC page
            if (!isProductionSubscriptionEnvironement(environment)) {
                inputCCInfo("", "", false, "", "", false, "", false, "", "", "", "", false, "", "", false);
            } else {
                //CC INFO FOR OTHER ENVIRONMENTS?
            }
            try {
                sel.assertLocatorText(new String[] { @"//span[@id='lastNameErr']" }, AugmentedSelenium.Set.All, AugmentedSelenium.Compare.Has, new String[] { "Required" });
                sel.assertLocatorText(new String[] { @"//span[@id='firstNameErr']" }, AugmentedSelenium.Set.All, AugmentedSelenium.Compare.Has, new String[] { "Required" });
                sel.assertLocatorText(new String[] { @"//span[@id='paymentAccountNumberErr']" }, AugmentedSelenium.Set.All, AugmentedSelenium.Compare.Has, new String[] { "Required" });
                sel.assertLocatorText(new String[] { @"//span[@id='billingAddressErr']" }, AugmentedSelenium.Set.All, AugmentedSelenium.Compare.Has, new String[] { "Required" });
                sel.assertLocatorText(new String[] { @"//span[@id='cityErr']" }, AugmentedSelenium.Set.All, AugmentedSelenium.Compare.Has, new String[] { "Required" });
                sel.assertLocatorText(new String[] { @"//span[@id='addressPostalCodeTextErr']" }, AugmentedSelenium.Set.All, AugmentedSelenium.Compare.Has, new String[] { "Required" });
                sel.assertLocatorExistence(new String[] { @"//div[@id='errorAcceptTerms' and @style='display:block;']" }, AugmentedSelenium.Set.None);
            } catch (TestAssertionException te) {
                String curLoc =sel.GetLocation(); 
                if (!isCurrentPageSpecifiedType(curLoc, OrderPageTypes.Payflow, path)) {
                    throw new TestAssertionException("Submitting bad data on CC info page navigated away from the page to " + curLoc);
                }
                te.addLineToDataBottom("Expected failure messaging not found");
                throw te;
            }
        }





        /// <summary>
        /// Navigates to CC input page with new account unless this orderpath is already on CC page. If it finds CC page,
        /// submits bad data and asserts error messaging response. If no CC page exists and flow instead goes directly to
        /// success page, the test defaults to passed.
        /// </summary>
        /// <param name="path"></param>
        private void testPayflowInvalidCredentialsOnlyName(OrderPath path) {
            //test if already on payflow page for this orderpath. Cannot be from another path since test state is cleared between each path
            if (!isCurrentPageSpecifiedType(sel.GetLocation(), OrderPageTypes.Payflow, path)) {
                sel.openPage( path.URL, true, true );
                String email = "qa_" + System.DateTime.Now.ToString("ss.mm.HH_dd.MM.yyyy") + @"@rhapsody.lan";
                inputOrderPathAccount(email, "password", "password", getCouponType(path), path, out email);
                OrderPageTypes curPageType = waitForPageType(path, new OrderPageTypes[] { OrderPageTypes.Payflow, OrderPageTypes.DifferedOffer, OrderPageTypes.Receipt, OrderPageTypes.TechDif, OrderPageTypes.SessionExpired }, 25000, 250);
                if (curPageType == OrderPageTypes.DifferedOffer) {//check for intermediate page
                    sel.SubmitForm( pageTypeTemplates[(int)(OrderPageTypes.DifferedOffer)].RuleValues[0][0][0] );
                    curPageType = waitForPageType(path, new OrderPageTypes[] { OrderPageTypes.Payflow, OrderPageTypes.Receipt, OrderPageTypes.TechDif, OrderPageTypes.SessionExpired }, 25000, 250);
                }
                if (curPageType == OrderPageTypes.Receipt) {
                    return;
                } else if (curPageType != OrderPageTypes.Payflow) {//at this point, can only validly be payflow
                    throw new TestAssertionException("Could not reach payflow page. Instead on " + curPageType.ToString());
                }
            }
            //on CC page
            if (!isProductionSubscriptionEnvironement(environment)) {
                inputCCInfo("fName", "lName", false, "", "", false, "", false, "", "", "", "", false, "", "", false);
            } else {
                //CC INFO FOR OTHER ENVIRONMENTS?
            }
            try {
                sel.assertLocatorExistence(new String[] { @"//span[@id='lastNameErr']" }, AugmentedSelenium.Set.None);
                sel.assertLocatorExistence(new String[] { @"//span[@id='firstNameErr']" }, AugmentedSelenium.Set.None);
                sel.assertLocatorText(new String[] { @"//span[@id='paymentAccountNumberErr']" }, AugmentedSelenium.Set.All, AugmentedSelenium.Compare.Has, new String[] { "Required" });
                sel.assertLocatorText(new String[] { @"//span[@id='billingAddressErr']" }, AugmentedSelenium.Set.All, AugmentedSelenium.Compare.Has, new String[] { "Required" });
                sel.assertLocatorText(new String[] { @"//span[@id='cityErr']" }, AugmentedSelenium.Set.All, AugmentedSelenium.Compare.Has, new String[] { "Required" });
                sel.assertLocatorText(new String[] { @"//span[@id='addressPostalCodeTextErr']" }, AugmentedSelenium.Set.All, AugmentedSelenium.Compare.Has, new String[] { "Required" });
                sel.assertLocatorExistence(new String[] { @"//div[@id='errorAcceptTerms' and @style='display:block;']" }, AugmentedSelenium.Set.None);
            } catch (TestAssertionException te) {
                String curLoc = sel.GetLocation();
                if (!isCurrentPageSpecifiedType(curLoc, OrderPageTypes.Payflow, path)) {
                    throw new TestAssertionException("Submitting bad data on CC info page navigated away from the page to " + curLoc);
                }
                te.addLineToDataBottom("Expected failure messaging not found");
                throw te;
            }
        }




        /// <summary>
        /// Navigates to CC input page with new account unless this orderpath is already on CC page. If it finds CC page,
        /// submits bad data and asserts error messaging response. If no CC page exists and flow instead goes directly to
        /// success page, the test defaults to passed.
        /// </summary>
        /// <param name="path"></param>
        private void testPayflowInvalidCredentialsMissingCCType(OrderPath path) {
            //test if already on payflow page for this orderpath. Cannot be from another path since test state is cleared between each path
            if (!isCurrentPageSpecifiedType(sel.GetLocation(), OrderPageTypes.Payflow, path)) {
                sel.openPage( path.URL, true, true );
                String email = "qa_" + System.DateTime.Now.ToString("ss.mm.HH_dd.MM.yyyy") + @"@rhapsody.lan";
                inputOrderPathAccount(email, "password", "password", getCouponType(path), path, out email);
                OrderPageTypes curPageType = waitForPageType(path, new OrderPageTypes[] { OrderPageTypes.Payflow, OrderPageTypes.DifferedOffer, OrderPageTypes.Receipt, OrderPageTypes.TechDif, OrderPageTypes.SessionExpired }, 25000, 250);
                if (curPageType == OrderPageTypes.DifferedOffer) {//check for intermediate page
                    sel.SubmitForm( pageTypeTemplates[(int)(OrderPageTypes.DifferedOffer)].RuleValues[0][0][0] );
                    curPageType = waitForPageType(path, new OrderPageTypes[] { OrderPageTypes.Payflow, OrderPageTypes.Receipt, OrderPageTypes.TechDif, OrderPageTypes.SessionExpired }, 25000, 250);
                }
                if (curPageType == OrderPageTypes.Receipt) {
                    return;
                } else if (curPageType != OrderPageTypes.Payflow) {//at this point, can only validly be payflow
                    throw new TestAssertionException("Could not reach payflow page. Instead on " + curPageType.ToString());
                }
            }
            //on CC page
            //new radio button payment method invalidates this test for templates that use it, break out early if that locator is found
            if(sel.isLocatorExistence(new String[]{pageTypeTemplates[(int)(OrderPageTypes.Payflow)].RuleValues[1][0][1]}, AugmentedSelenium.Set.AllSome)){
                return;
            }
            if (!isProductionSubscriptionEnvironement(environment)) {
                inputCCInfo("fName", "lName", false, "", "4111111111111111", false, "", false, "", "1234567890", "Timbuktu", "Seattle", false, "", "97007", false);
            } else {
                //CC INFO FOR OTHER ENVIRONMENTS?
            }
            try {
                sel.assertLocatorExistence(new String[] { @"//span[@id='firstNameErr']" }, AugmentedSelenium.Set.None);
                sel.assertLocatorExistence(new String[] { @"//span[@id='lastNameErr']" }, AugmentedSelenium.Set.None);
                sel.assertLocatorExistence(new String[] { @"//span[@id='paymentAccountNumberErr']" }, AugmentedSelenium.Set.None);
                sel.assertLocatorExistence(new String[] { @"//span[@id='billingAddressErr']" }, AugmentedSelenium.Set.None);
                sel.assertLocatorExistence(new String[] { @"//span[@id='cityErr']" }, AugmentedSelenium.Set.None);
                sel.assertLocatorExistence(new String[] { @"//span[@id='addressPostalCodeTextErr']" }, AugmentedSelenium.Set.None);
                String errorElement = sel.getFirstExistingElement(new String[] { @"//div[@class='warning globalErrors']//li[1]", @"//div[@id='errors']//li[1]" });
                sel.assertLocatorText(new String[] { errorElement }, AugmentedSelenium.Set.All, AugmentedSelenium.Compare.Has, new String[] { "Payment subtype is not valid." });
                sel.assertLocatorExistence(new String[] { @"//div[@id='errorAcceptTerms' and @style='display:block;']" }, AugmentedSelenium.Set.None);
            } catch (TestAssertionException te) {
                String curLoc = sel.GetLocation();
                if (!isCurrentPageSpecifiedType(curLoc, OrderPageTypes.Payflow, path)) {
                    throw new TestAssertionException("Submitting bad data on CC info page navigated away from the page to " + curLoc);
                }
                te.addLineToDataBottom("Expected failure messaging not found");
                throw te;
            }
        }





        /// <summary>
        /// Navigates to CC input page with new account unless this orderpath is already on CC page. If it finds CC page,
        /// submits bad data and asserts error messaging response. If no CC page exists and flow instead goes directly to
        /// success page, the test defaults to passed.
        /// </summary>
        /// <param name="path"></param>
        private void testPayflowInvalidCredentialsMissingState(OrderPath path) {
            //test if already on payflow page for this orderpath. Cannot be from another path since test state is cleared between each path
            if (!isCurrentPageSpecifiedType(sel.GetLocation(), OrderPageTypes.Payflow, path)) {
                sel.openPage( path.URL, true, true );
                String email = "qa_" + System.DateTime.Now.ToString("ss.mm.HH_dd.MM.yyyy") + @"@rhapsody.lan";
                inputOrderPathAccount(email, "password", "password", getCouponType(path), path, out email);
                OrderPageTypes curPageType = waitForPageType(path, new OrderPageTypes[] { OrderPageTypes.Payflow, OrderPageTypes.DifferedOffer, OrderPageTypes.Receipt, OrderPageTypes.TechDif, OrderPageTypes.SessionExpired }, 25000, 250);
                if (curPageType == OrderPageTypes.DifferedOffer) {//check for intermediate page
                    sel.SubmitForm( pageTypeTemplates[(int)(OrderPageTypes.DifferedOffer)].RuleValues[0][0][0] );
                    curPageType = waitForPageType(path, new OrderPageTypes[] { OrderPageTypes.Payflow, OrderPageTypes.Receipt, OrderPageTypes.TechDif, OrderPageTypes.SessionExpired }, 25000, 250);
                }
                if (curPageType == OrderPageTypes.Receipt) {
                    return;
                } else if (curPageType != OrderPageTypes.Payflow) {//at this point, can only validly be payflow
                    throw new TestAssertionException("Could not reach payflow page. Instead on " + curPageType.ToString());
                }
            }
            //on CC page
            if (!isProductionSubscriptionEnvironement(environment)) {
                inputCCInfo("fName", "lName", true, "Visa", "4111111111111111", false, "", false, "", "1234567890", "Timbuktu", "Seattle", false, "", "97007", false);
            } else {
                //CC INFO FOR OTHER ENVIRONMENTS?
            }
            try {
                sel.assertLocatorExistence(new String[] { @"//span[@id='firstNameErr']" }, AugmentedSelenium.Set.None);
                sel.assertLocatorExistence(new String[] { @"//span[@id='lastNameErr']" }, AugmentedSelenium.Set.None);
                sel.assertLocatorExistence(new String[] { @"//span[@id='paymentAccountNumberErr']" }, AugmentedSelenium.Set.None);
                sel.assertLocatorExistence(new String[] { @"//span[@id='billingAddressErr']" }, AugmentedSelenium.Set.None);
                sel.assertLocatorExistence(new String[] { @"//span[@id='cityErr']" }, AugmentedSelenium.Set.None);
                String stateCurrentValue = sel.GetSelectedValue(@"//select[@id='addressStateMenu']");
                if (!stateCurrentValue.Equals("alabama", StringComparison.OrdinalIgnoreCase) && !stateCurrentValue.Equals("AL", StringComparison.OrdinalIgnoreCase)) {
                    sel.assertLocatorExistence(new String[] { @"//span[@id='addressPostalCodeTextErr']" }, AugmentedSelenium.Set.None);
                    sel.assertLocatorText(new String[] { @"//span[@id='addressStateMenuErr']" }, AugmentedSelenium.Set.All, AugmentedSelenium.Compare.Has, new String[] { "Please provide a valid state." });
                }
                sel.assertLocatorExistence(new String[] { @"//div[@id='errorAcceptTerms' and @style='display:block;']" }, AugmentedSelenium.Set.None);
            } catch (TestAssertionException te) {
                String curLoc = sel.GetLocation();
                if (!isCurrentPageSpecifiedType(curLoc, OrderPageTypes.Payflow, path)) {
                    throw new TestAssertionException("Submitting bad data on CC info page navigated away from the page to " + curLoc);
                }
                te.addLineToDataBottom("Expected failure messaging not found");
                throw te;
            }
        }





        /// <summary>
        /// Navigates to CC input page with new account unless this orderpath is already on CC page. If it finds CC page,
        /// submits bad data and asserts error messaging response. If no CC page exists and flow instead goes directly to
        /// success page, the test defaults to passed.
        /// </summary>
        /// <param name="path"></param>
        private void testPayflowInvalidCredentialsInvalidZip(OrderPath path) {
            //test if already on payflow page for this orderpath. Cannot be from another path since test state is cleared between each path
            if (!isCurrentPageSpecifiedType(sel.GetLocation(), OrderPageTypes.Payflow, path)) {
                sel.openPage( path.URL, true, true );
                String email = "qa_" + System.DateTime.Now.ToString("ss.mm.HH_dd.MM.yyyy") + @"@rhapsody.lan";
                inputOrderPathAccount(email, "password", "password", getCouponType(path), path, out email);
                OrderPageTypes curPageType = waitForPageType(path, new OrderPageTypes[] { OrderPageTypes.Payflow, OrderPageTypes.DifferedOffer, OrderPageTypes.Receipt, OrderPageTypes.TechDif, OrderPageTypes.SessionExpired }, 25000, 250);
                if (curPageType == OrderPageTypes.DifferedOffer) {//check for intermediate page
                    sel.SubmitForm( pageTypeTemplates[(int)(OrderPageTypes.DifferedOffer)].RuleValues[0][0][0] );
                    curPageType = waitForPageType(path, new OrderPageTypes[] { OrderPageTypes.Payflow, OrderPageTypes.Receipt, OrderPageTypes.TechDif, OrderPageTypes.SessionExpired }, 25000, 250);
                }
                if (curPageType == OrderPageTypes.Receipt) {
                    return;
                } else if (curPageType != OrderPageTypes.Payflow) {//at this point, can only validly be payflow
                    throw new TestAssertionException("Could not reach payflow page. Instead on " + curPageType.ToString());
                }
            }
            //on CC page
            if (!isProductionSubscriptionEnvironement(environment)) {
                inputCCInfo("fName", "lName", true, "Visa", "4111111111111111", false, "", false, "", "1234567890", "Timbuktu", "Seattle", true, "Oregon", "badZip", false);
            } else {
                //CC INFO FOR OTHER ENVIRONMENTS?
            }
            try {
                sel.assertLocatorExistence(new String[] { @"//span[@id='firstNameErr']" }, AugmentedSelenium.Set.None);
                sel.assertLocatorExistence(new String[] { @"//span[@id='lastNameErr']" }, AugmentedSelenium.Set.None);
                sel.assertLocatorExistence(new String[] { @"//span[@id='paymentAccountNumberErr']" }, AugmentedSelenium.Set.None);
                sel.assertLocatorExistence(new String[] { @"//span[@id='billingAddressErr']" }, AugmentedSelenium.Set.None);
                sel.assertLocatorExistence(new String[] { @"//span[@id='cityErr']" }, AugmentedSelenium.Set.None);
                sel.assertLocatorText(new String[] { @"//span[@id='addressPostalCodeTextErr']" }, AugmentedSelenium.Set.All, AugmentedSelenium.Compare.Has, new String[] { "Invalid postal code." });
                sel.assertLocatorExistence(new String[] { @"//span[@id='addressStateMenuErr']" }, AugmentedSelenium.Set.None);
                sel.assertLocatorExistence(new String[] { @"//div[@id='errorAcceptTerms' and @style='display:block;']" }, AugmentedSelenium.Set.None);
            } catch (TestAssertionException te) {
                String curLoc = sel.GetLocation();
                if (!isCurrentPageSpecifiedType(curLoc, OrderPageTypes.Payflow, path)) {
                    throw new TestAssertionException("Submitting bad data on CC info page navigated away from the page to " + curLoc);
                }
                te.addLineToDataBottom("Expected failure messaging not found");
                throw te;
            }
        }




        /// <summary>
        /// Navigates to CC input page with new account unless this orderpath is already on CC page. If it finds CC page,
        /// submits bad data and asserts error messaging response. If no CC page exists and flow instead goes directly to
        /// success page, the test defaults to passed.
        /// </summary>
        /// <param name="path"></param>
        private void testPayflowInvalidCredentialsInvalidCCNumber(OrderPath path) {
            //test if already on payflow page for this orderpath. Cannot be from another path since test state is cleared between each path
            if (!isCurrentPageSpecifiedType(sel.GetLocation(), OrderPageTypes.Payflow, path)) {
                sel.openPage( path.URL, true, true );
                String email = "qa_" + System.DateTime.Now.ToString("ss.mm.HH_dd.MM.yyyy") + @"@rhapsody.lan";
                inputOrderPathAccount(email, "password", "password", getCouponType(path), path, out email);
                OrderPageTypes curPageType = waitForPageType(path, new OrderPageTypes[] { OrderPageTypes.Payflow, OrderPageTypes.DifferedOffer, OrderPageTypes.Receipt, OrderPageTypes.TechDif, OrderPageTypes.SessionExpired }, 25000, 250);
                if (curPageType == OrderPageTypes.DifferedOffer) {//check for intermediate page
                    sel.SubmitForm( pageTypeTemplates[(int)(OrderPageTypes.DifferedOffer)].RuleValues[0][0][0] );
                    curPageType = waitForPageType(path, new OrderPageTypes[] { OrderPageTypes.Payflow, OrderPageTypes.Receipt, OrderPageTypes.TechDif, OrderPageTypes.SessionExpired }, 25000, 250);
                }
                if (curPageType == OrderPageTypes.Receipt) {
                    return;
                } else if (curPageType != OrderPageTypes.Payflow) {//at this point, can only validly be payflow
                    throw new TestAssertionException("Could not reach payflow page. Instead on " + curPageType.ToString());
                }
            }
            //on CC page
            if (!isProductionSubscriptionEnvironement(environment)) {
                inputCCInfo("fName", "lName", true, "Visa", "iulgliug", false, "", false, "", "1234567890", "Timbuktu", "Seattle", true, "Oregon", "97007", false);
            } else {
                //CC INFO FOR OTHER ENVIRONMENTS?
            }
            try {
                sel.assertLocatorExistence(new String[] { @"//span[@id='firstNameErr']" }, AugmentedSelenium.Set.None);
                sel.assertLocatorExistence(new String[] { @"//span[@id='lastNameErr']" }, AugmentedSelenium.Set.None);
                sel.assertLocatorExistence(new String[] { @"//span[@id='paymentAccountNumberErr']" }, AugmentedSelenium.Set.None);
                sel.assertLocatorExistence(new String[] { @"//span[@id='billingAddressErr']" }, AugmentedSelenium.Set.None);
                sel.assertLocatorExistence(new String[] { @"//span[@id='cityErr']" }, AugmentedSelenium.Set.None);
                sel.assertLocatorExistence(new String[] { @"//span[@id='addressPostalCodeTextErr']" }, AugmentedSelenium.Set.None);
                String errorElement = sel.getFirstExistingElement(new String[] { @"//div[@class='warning globalErrors']//li[1]", @"//div[@id='errors']//li[1]" });
                sel.assertLocatorText(new String[] { errorElement }, AugmentedSelenium.Set.All, AugmentedSelenium.Compare.Has, new String[] { "Invalid account number." });
                sel.assertLocatorExistence(new String[] { @"//span[@id='addressStateMenuErr']" }, AugmentedSelenium.Set.None);
                sel.assertLocatorExistence(new String[] { @"//div[@id='errorAcceptTerms' and @style='display:block;']" }, AugmentedSelenium.Set.None);
            } catch (TestAssertionException te) {
                String curLoc = sel.GetLocation();
                if (!isCurrentPageSpecifiedType(curLoc, OrderPageTypes.Payflow, path)) {
                    throw new TestAssertionException("Submitting bad data on CC info page navigated away from the page to " + curLoc);
                }
                te.addLineToDataBottom("Expected failure messaging not found");
                throw te;
            }
        }






        /// <summary>
        /// Navigates to CC input page with new account unless this orderpath is already on CC page. If it finds CC page,
        /// submits bad data and asserts error messaging response. If no CC page exists and flow instead goes directly to
        /// success page, the test defaults to passed.
        /// </summary>
        /// <param name="path"></param>
        private void testPayflowInvalidCredentialsExpiredCCDate(OrderPath path) {
            //test if already on payflow page for this orderpath. Cannot be from another path since test state is cleared between each path
            if (!isCurrentPageSpecifiedType(sel.GetLocation(), OrderPageTypes.Payflow, path)) {
                sel.openPage(path.URL, true, true);
                String email = "qa_" + System.DateTime.Now.ToString("ss.mm.HH_dd.MM.yyyy") + @"@rhapsody.lan";
                inputOrderPathAccount(email, "password", "password", getCouponType(path), path, out email);
                OrderPageTypes curPageType = waitForPageType(path, new OrderPageTypes[] { OrderPageTypes.Payflow, OrderPageTypes.DifferedOffer, OrderPageTypes.Receipt, OrderPageTypes.TechDif, OrderPageTypes.SessionExpired }, 25000, 250);
                if (curPageType == OrderPageTypes.DifferedOffer) {//check for intermediate page
                    sel.SubmitForm( pageTypeTemplates[(int)(OrderPageTypes.DifferedOffer)].RuleValues[0][0][0] );
                    curPageType = waitForPageType(path, new OrderPageTypes[] { OrderPageTypes.Payflow, OrderPageTypes.Receipt, OrderPageTypes.TechDif, OrderPageTypes.SessionExpired }, 25000, 250);
                }
                if (curPageType == OrderPageTypes.Receipt) {
                    return;
                } else if (curPageType != OrderPageTypes.Payflow) {//at this point, can only validly be payflow
                    throw new TestAssertionException("Could not reach payflow page. Instead on " + curPageType.ToString());
                }
            }
            //on CC page
            if (!isProductionSubscriptionEnvironement(environment)) {
                inputCCInfo("fName", "lName", true, "Visa", "4111111111111111", true, "1", true, DateTime.Now.Year.ToString(), "1234567890", "Timbuktu", "Seattle", true, "Oregon", "97007", false);
            } else {
                //CC INFO FOR OTHER ENVIRONMENTS?
            }
            try {
                sel.assertLocatorExistence(new String[] { @"//span[@id='firstNameErr']" }, AugmentedSelenium.Set.None);
                sel.assertLocatorExistence(new String[] { @"//span[@id='lastNameErr']" }, AugmentedSelenium.Set.None);
                sel.assertLocatorExistence(new String[] { @"//span[@id='paymentAccountNumberErr']" }, AugmentedSelenium.Set.None);
                sel.assertLocatorExistence(new String[] { @"//span[@id='billingAddressErr']" }, AugmentedSelenium.Set.None);
                sel.assertLocatorExistence(new String[] { @"//span[@id='cityErr']" }, AugmentedSelenium.Set.None);
                sel.assertLocatorExistence(new String[] { @"//span[@id='addressPostalCodeTextErr']" }, AugmentedSelenium.Set.None);
                sel.assertLocatorExistence(new String[] { @"//span[@id='addressStateMenuErr']" }, AugmentedSelenium.Set.None);
                String errorElement = sel.getFirstExistingElement(new String[] { @"//div[@class='warning globalErrors']//li[1]", @"//div[@id='errors']//li[1]" });
                sel.assertLocatorText(new String[] { errorElement }, AugmentedSelenium.Set.All, AugmentedSelenium.Compare.Has, new String[] { @"Expiration year/month " + DateTime.Now.Year.ToString() + @"/1 is in the past" });
                sel.assertLocatorExistence(new String[] { @"//div[@id='errorAcceptTerms' and @style='display:block;']" }, AugmentedSelenium.Set.None);
            } catch (TestAssertionException te) {
                String curLoc = sel.GetLocation();
                if (!isCurrentPageSpecifiedType(curLoc, OrderPageTypes.Payflow, path)) {
                    throw new TestAssertionException("Submitting bad data on CC info page navigated away from the page to " + curLoc);
                }
                te.addLineToDataBottom("Expected failure messaging not found");
                throw te;
            }
        }



        private void testPayflowInvalidCredentialsMissingSubscriptionTermsCheckbox(OrderPath path) {
            //test if already on payflow page for this orderpath. Cannot be from another path since test state is cleared between each path
            if (!isCurrentPageSpecifiedType(sel.GetLocation(), OrderPageTypes.Payflow, path)) {
                sel.openPage( path.URL, true, true );
                String email = "qa_" + System.DateTime.Now.ToString("ss.mm.HH_dd.MM.yyyy") + @"@rhapsody.lan";
                inputOrderPathAccount(email, "password", "password", getCouponType(path), path, out email);
                OrderPageTypes curPageType = waitForPageType(path, new OrderPageTypes[] { OrderPageTypes.Payflow, OrderPageTypes.DifferedOffer, OrderPageTypes.Receipt, OrderPageTypes.TechDif, OrderPageTypes.SessionExpired }, 25000, 250);
                if (curPageType == OrderPageTypes.DifferedOffer) {//check for intermediate page
                    sel.SubmitForm( pageTypeTemplates[(int)(OrderPageTypes.DifferedOffer)].RuleValues[0][0][0] );
                    curPageType = waitForPageType(path, new OrderPageTypes[] { OrderPageTypes.Payflow, OrderPageTypes.Receipt, OrderPageTypes.TechDif, OrderPageTypes.SessionExpired }, 25000, 250);
                }
                if (curPageType == OrderPageTypes.Receipt) {
                    return;
                } else if (curPageType != OrderPageTypes.Payflow) {//at this point, can only validly be payflow
                    throw new TestAssertionException("Could not reach payflow page. Instead on " + curPageType.ToString());
                }
            }
            //on CC page
            if (!isProductionSubscriptionEnvironement(environment)) {
                inputCCInfo("fName", "lName", true, "Visa", "4111111111111111", true, "12", true, "2024", "1234567890", "Timbuktu", "Seattle", true, AgreementRequiredStates.Washington.ToString(), "98103", false);
            } else {
                //CC INFO FOR OTHER ENVIRONMENTS?
            }
            try {
                sel.assertLocatorText(new String[] { @"//span[@id='lastNameErr']" }, AugmentedSelenium.Set.None, AugmentedSelenium.Compare.Has, new String[] { "Required" });
                sel.assertLocatorText(new String[] { @"//span[@id='firstNameErr']" }, AugmentedSelenium.Set.None, AugmentedSelenium.Compare.Has, new String[] { "Required" });
                sel.assertLocatorText(new String[] { @"//span[@id='paymentAccountNumberErr']" }, AugmentedSelenium.Set.None, AugmentedSelenium.Compare.Has, new String[] { "Required" });
                sel.assertLocatorText(new String[] { @"//span[@id='billingAddressErr']" }, AugmentedSelenium.Set.None, AugmentedSelenium.Compare.Has, new String[] { "Required" });
                sel.assertLocatorText(new String[] { @"//span[@id='cityErr']" }, AugmentedSelenium.Set.None, AugmentedSelenium.Compare.Has, new String[] { "Required" });
                sel.assertLocatorText(new String[] { @"//span[@id='addressPostalCodeTextErr']" }, AugmentedSelenium.Set.None, AugmentedSelenium.Compare.Has, new String[] { "Required" });
                sel.assertLocatorExistence(new String[] { @"//div[@id='errorAcceptTerms' and @style='display: block;']/p[1]" }, AugmentedSelenium.Set.All);//text is constant, only the style changes so watch that instead
            } catch (TestAssertionException te) {
                String curLoc = sel.GetLocation();
                if (!isCurrentPageSpecifiedType(curLoc, OrderPageTypes.Payflow, path)) {
                    throw new TestAssertionException("Submitting bad data on CC info page navigated away from the page to " + curLoc);
                }
                te.addLineToDataBottom("Expected failure messaging not found");
                throw te;
            }
        }
        #endregion






        #region track purchase tests
        private void buyOrderPathTrack(OrderPath path) {
            /*
            openPage(path.URL, true, false);
            String email = "qa_" + System.DateTime.Now.ToString("ss.mm.HH_dd.MM.yyyy") + @"@rhapsody.lan";
            inputOrderPathAccount(email, "password", "password", getCouponType(path));
            if (!isProductionSubscriptionEnvironement(environment)) {
                inputCCInfo("fName", "lName", true, "Visa", "4111111111111111", true, "12", true, "2024", "1234567890", "Timbuktu", "Seattle", true, "Washington", "98103");
            } else {
                //CC INFO FOR OTHER ENVIRONMENTS?
            }
            sel.WaitForPageToLoad("25000");
            sel.assertPresentLocation(path.URL, true);
            sel.assertTextForElementHasValue(@"//li[@class='three ']", "Start listening");
            sel.assertTextForElementHasValue(@"//div[@class='receipt']/div[2]/h2[1]", "Thanks for joining Rhapsody!");
            */



            sel.openPage(path.URL, true, true );
            String email = "qa_" + System.DateTime.Now.ToString("ss.mm.HH_dd.MM.yyyy") + @"@rhapsody.lan";
            bool isCouponPath = !getCouponType(path).Equals("");
            String[] couponSuccessMessages = new String[] { "Credit Redemption:", "Your Account has been updated", "Thank You", "Your account has been updated", "Thanks for joining Rhapsody!", "Rhapsody Pre-Paid Membership: Thanks for joining Rhapsody!" };
            String[] successMessages = new String[] { "Thanks for joining Rhapsody!", "Rhapsody To Go: Free Trial", "Rhapsody Premier: Free Trial", "Thank You!", "Rhapsody To Go: Sign Up", "Rhapsody: Sign Up", "Rhapsody Premier: Sign Up", "Rhapsody Premier Plus: Sign Up", "Rhapsody MP3 Account", "Welcome to Rhapsody" };//trial and non trial, separate later
            
            //String[] acceptedURLS = new String[] { path.URL, path.URL.Replace(@"realstore/", "") };

            inputOrderPathAccount(email, "password", "password", getCouponType(path), path, out email);

            //check for intermediate page
            if (isCurrentPageSpecifiedType(sel.GetLocation(), OrderPageTypes.DifferedOffer, path)) {
                sel.SubmitForm( pageTypeTemplates[(int)(OrderPageTypes.DifferedOffer)].RuleValues[0][0][0] );
                sel.WaitForPageToLoad("25000");
            }

            //wait for identifying element of any next page type
            sel.waitForLocatorExistence(new String[] { @"//input[@id='firstName']", @"//div[@id='pageTitleExistingUser']", @"//div[@id='contentHeadline']", @"//div[@class='receipt']", @"//div[@class='pSub']", @"//div[@id='contentHeadline']", @"//div[@id='content']/h1[1]" }, AugmentedSelenium.Set.AllSome, 25000, 200);//sel.tryWaitForAnyOneElementToExist(new String[] { @"//input[@id='firstName']", @"//div[@id='pageTitleExistingUser']", @"//div[@id='contentHeadline']", @"//div[@class='receipt']", @"//div[@class='pSub']", @"//div[@id='contentHeadline']", @"//div[@id='content']/h1[1]" }, 25000, 200);

            //check for early no cc completion page
            if (!sel.IsElementPresent(@"//input[@id='firstName']") && isCurrentPageSpecifiedType(sel.GetLocation(), OrderPageTypes.Receipt, path)) {
                try {
                    if (isCouponPath) {
                        String pageSuccessMessagingLocator = sel.getFirstExistingElement(new String[] { @"//div[@id='pageTitleExistingUser']", @"//div[@id='contentHeadline']", @"//div[@id='pageTitle']" });
                        sel.assertLocatorText(new String[]{pageSuccessMessagingLocator}, AugmentedSelenium.Set.AllSome, AugmentedSelenium.Compare.Has, couponSuccessMessages);//sel.assertTextForElementMatchesAnyValue(pageSuccessMessagingLocator, couponSuccessMessages);
                    } else {
                        String pageSuccessMessagingLocator = sel.getFirstExistingElement(new String[] { @"//div[@class='receipt']/h1[1]", @"//div[@class='pSub']", @"//div[@id='contentHeadline']" });
                        sel.assertLocatorText(new String[] { pageSuccessMessagingLocator }, AugmentedSelenium.Set.AllSome, AugmentedSelenium.Compare.Has, successMessages);//sel.assertTextForElementMatchesAnyValue(pageSuccessMessagingLocator, successMessages);
                    }
                } catch (TestAssertionException te) {
                    te.addLineToDataTop("orderpath completion page through no CC page");
                    throw te;
                } catch (Exception e) {
                    Exception newMessage = new Exception("orderpath completion through CC to trial expired flow", e);
                    throw newMessage;
                }
                //SUCCESSFUL ORDERPATH PAGES (just need the page elements to exist, not necessarily have successful text messaging)
                //div class receipt / H1 "Rhapsody To Go: Free Trial"
                //div class receipt / H1 "Rhapsody Premier: Free Trial"
                //div class receipt / H1 "Thank You!"
                //div class pSub  "Thank You!"
                //COUPON
                //div id pageTitle(ExistingUser?) "Coupon Redemption"
                //div id contentHeadline "Your Account has been updated"
                //div id pageTitleExistingUser "Thank You"
                //div id pageTitleExistingUser "Your account has been updated"
                //div id pageTitleExistingUser "Thanks for joining Rhapsody!"
                return;
            }

            //on CC page or failed through from above, either way assert on CC page and go through it to completion
            if (!isProductionSubscriptionEnvironement(environment)) {
                inputCCInfo("fName", "lName", true, "Visa", "4111111111111111", true, "12", true, "2024", "1234567890", "Timbuktu", "Seattle", true, "Washington", "98103", false);
            } else {
                //CC INFO FOR OTHER ENVIRONMENTS?
            }

            if (path.Trial) {
                try {
                    sel.waitForLocatorExistence(new String[] { @"//input[@id='continueButton']", @"//input[@id='startDownload']" }, AugmentedSelenium.Set.AllSome, 25000, 200);//sel.tryWaitForAnyOneElementToExist(new String[] { @"//input[@id='continueButton']", @"//input[@id='startDownload']" }, 25000, 200); 
                    sel.assertLocatorExistence(new String[] { @"//input[@id='continueButton']", @"//input[@id='startDownload']" }, AugmentedSelenium.Set.AllSome);//sel.assertElementsSomeExist(new String[] { @"//input[@id='continueButton']", @"//input[@id='startDownload']" });
                    sel.Click(sel.getFirstExistingElement(new String[] { @"//input[@id='continueButton']", @"//input[@id='startDownload']" }));
                    sel.WaitForPageToLoad("25000");
                    if (isCurrentPageSpecifiedType(sel.GetLocation(), OrderPageTypes.Receipt, path)) {
                        return;
                    }
                    inputCCInfo("fName", "lName", true, "Visa", "4111111111111111", true, "12", true, "2024", "1234567890", "Timbuktu", "Seattle", true, "Washington", "98103", false);
                } catch (Exception e) {
                    String message = "orderpath completion through CC to trial expired flow";
                    try {
                        if (isCurrentPageSpecifiedType(sel.GetLocation(), OrderPageTypes.TechDif, path)) {
                            message += " - technical difficulties";
                        }
                    } catch (Exception ) { }
                    if (e.GetType().Equals(typeof(TestAssertionException))) {
                        ((TestAssertionException)e).addLineToDataTop(message);
                        throw e;
                    } else {
                        Exception newMessage = new Exception(message, e);
                        throw newMessage;
                    }
                }

            } 
            //should be signed up now, any valid no CC path should have exited


            sel.Open(mp3StoreURI.AbsoluteUri + @"/home.html");
            sel.WaitForPageToLoad("25000");
            sel.assertPresentLocation(mp3StoreURI.AbsoluteUri + @"/home.html");
            
            String albumName = clickHomePageBuyButton();
            clickCheckoutButton();

            //password verification page(even though was signed in)
            sel.assertPresentLocation( mp3PurchaseFlowFullURI.AbsoluteUri, true );
            sel.waitForLocatorExistence(new String[] { @"//input[@id='password']" }, AugmentedSelenium.Set.AllSome, 25000, 200);//sel.tryWaitForElementToExist(@"//input[@id='password']", 25000, 200);
            sel.Type(@"//input[@id='password']", "password");
            sel.waitForLocatorExistence(new String[] { @"//input[@id='continueButton']" }, AugmentedSelenium.Set.AllSome, 25000, 200);//sel.waitForLocatorExistence(new String[] { @"//input[@id='continueButton']" }, AugmentedSelenium.Set.AllSome, 25000, 200);//sel.tryWaitForElementToExist(@"//input[@id='continueButton']", 25000, 200);

            
                    

            sel.Click(@"//input[@id='continueButton']");

            //purchase verification page
            sel.assertPresentLocation( mp3PurchaseFlowFullURI.AbsoluteUri, true );
            sel.waitForLocatorExistence(new String[] { @"//input[@id='continueButton']" }, AugmentedSelenium.Set.AllSome, 25000, 200);//sel.tryWaitForElementToExist(@"//input[@id='continueButton']", 25000, 200);
            sel.Click(@"//input[@id='continueButton']");

            //missing click input name= checkoutButton on the url: http://realstore.int.rhapsody.com/rhapsody/mp3store?_flowExecutionKey=_...

            sel.openIfNotAt(mp3StoreURI.AbsoluteUri+ @"/mydownloads.html", false);
            sel.WaitForPageToLoad("25000");
            sel.waitForLocatorExistence(new String[] { @"//div[@class='artistPageTracksTableHolder']/table[1]/tbody[1]/tr[2]/td[4]" }, AugmentedSelenium.Set.AllSome, 25000, 200);//sel.tryWaitForElementToExist(@"//div[@class='artistPageTracksTableHolder']/table[1]/tbody[1]/tr[2]/td[4]", 25000, 200);

            try {
                sel.assertLocatorText(new String[] { @"//div[@class='artistPageTracksTableHolder']/table[1]/tbody[1]/tr[2]/td[4]" }, AugmentedSelenium.Set.All, AugmentedSelenium.Compare.Has, new String[] { albumName });//sel.assertTextForElementHasValue(@"//div[@class='artistPageTracksTableHolder']/table[1]/tbody[1]/tr[2]/td[4]", albumName);
            } catch (TestAssertionException e) {
                e.addLineToDataTop("Fail: " + email + " has failed to purchase purchased the album " + albumName);
                throw e;
            }
        }
        #endregion






        #region sign in tests
        /// <summary>
        /// Checks if already on sign in page, or opens sign in link if not,
        /// then enters valid account credentials.
        /// Expects no tech dif page, and no sign in page.
        /// </summary>
        /// <param name="path"></param>
        private void testSignInValidCredentialsExistingUser(OrderPath path) {
            String email = EXISTING_RHAP_ACCOUNTNAME;
            if(path.isCouponPath()) {
                //create new account that has never used a coupon
                try {
                    email = "qa_" + System.DateTime.Now.ToString("ss.mm.HH_dd.MM.yyyy") + @"@rhapsody.lan";
                    sel.openPage(R25PATH.URL, true, true);
                    inputOrderPathAccount(email, "password", "password", getCouponType(path), R25PATH, out email);
                } catch(TestAssertionException te) {
                    te.addLineToDataTop("Unable to create new account to use to sign in on coupon path");
                    throw te;
                }
            }
            //check if already on sign in page
            if(!isCurrentPageSpecifiedType(sel.GetLocation(), OrderPageTypes.SignIn, path)){
                sel.openPage(path.URL, true, true);
                //check if opened page is on sign in or sign up page
                if(isCurrentPageSpecifiedType(sel.GetLocation(), OrderPageTypes.SignUp, path)){
                    sel.Click(sel.getFirstExistingElement(pageTypeTemplates[(int)(OrderPageTypes.SignUp)].RuleValues[5][0]));
                    waitForPageType(path, new OrderPageTypes[] { OrderPageTypes.SignIn, OrderPageTypes.SignUp }, 2500, 300);//doesn't open a new page, just reworks signup/signin
                }
                assertCurrentPageIsExpectedType(new OrderPageTypes[] { OrderPageTypes.SignIn }, path);
            }
            //on sign in so now or exited function, try the account
            signIn(email, "password",getCouponType(path));
            //assert not on sign in page
            OrderPageTypes curPage = waitForPageType(path, new OrderPageTypes[] { OrderPageTypes.AlreadyMember, OrderPageTypes.Payflow, OrderPageTypes.Receipt, OrderPageTypes.DifferedOffer, OrderPageTypes.TrialExpired, OrderPageTypes.SignIn, OrderPageTypes.TechDif, OrderPageTypes.UnavailableMembership }, 10000, 500);
            assertCurrentPageIsExpectedType(curPage, new OrderPageTypes[] { OrderPageTypes.Payflow, OrderPageTypes.Receipt, OrderPageTypes.AlreadyMember, OrderPageTypes.DifferedOffer, OrderPageTypes.TrialExpired, OrderPageTypes.UnavailableMembership });
        }



        /// <summary>
        /// existing email, no password
        /// </summary>
        /// <param name="path"></param>
        private void testSignInInvalidCredentialsNoPassword(OrderPath path) {
            //check if already on sign in page
            if(!isCurrentPageSpecifiedType(sel.GetLocation(), OrderPageTypes.SignIn, path)) {
                sel.openPage(path.URL, true, true);
                //check if opened page is on sign in or sign up page
                if(isCurrentPageSpecifiedType(sel.GetLocation(), OrderPageTypes.SignUp, path)) {
                    sel.Click(sel.getFirstExistingElement(pageTypeTemplates[(int)(OrderPageTypes.SignUp)].RuleValues[5][0]));
                    waitForPageType(path, new OrderPageTypes[] { OrderPageTypes.SignIn, OrderPageTypes.SignUp }, 2500, 300);//doesn't open a new page, just reworks signup/signin
                }
                assertCurrentPageIsExpectedType(new OrderPageTypes[] { OrderPageTypes.SignIn }, path);
            }
            //on sign in so now or exited function, try the account
            signIn(EXISTING_RHAP_ACCOUNTNAME, "", getCouponType(path));
            //assert on sign in page and error messaging exists
            OrderPageTypes curPage = waitForPageType(path, new OrderPageTypes[] { OrderPageTypes.SignIn, OrderPageTypes.TechDif, OrderPageTypes.Payflow, OrderPageTypes.Receipt }, 1000, 500);
            assertCurrentPageIsExpectedType(curPage, new OrderPageTypes[] { OrderPageTypes.SignIn });
            sel.assertLocatorText(new String[] { @"//div[@id='loginPageErrorsText']/p[@class='warning']", @"//div[@id='loginPageErrorsText']/p[2]" }, AugmentedSelenium.Set.All, AugmentedSelenium.Compare.Has, new String[] { "Please correct the error(s) listed below and resubmit your form", "Password was left blank" });
        }



        /// <summary>
        /// existing account email, wrong password
        /// </summary>
        /// <param name="path"></param>
        private void testSignInInvalidCredentialsWrongPassword(OrderPath path) {
            //check if already on sign in page
            if(!isCurrentPageSpecifiedType(sel.GetLocation(), OrderPageTypes.SignIn, path)) {
                sel.openPage(path.URL, true, true);
                //check if opened page is on sign in or sign up page
                if(isCurrentPageSpecifiedType(sel.GetLocation(), OrderPageTypes.SignUp, path)) {
                    
                    sel.Click(sel.getFirstExistingElement(pageTypeTemplates[(int)(OrderPageTypes.SignUp)].RuleValues[5][0]));
                    waitForPageType(path, new OrderPageTypes[] { OrderPageTypes.SignIn, OrderPageTypes.SignUp }, 2500, 300);//doesn't open a new page, just reworks signup/signin
                }
                assertCurrentPageIsExpectedType(new OrderPageTypes[] { OrderPageTypes.SignIn }, path);
            }
            //on sign in so now or exited function, try the account
            signIn(EXISTING_RHAP_ACCOUNTNAME, "passwordIncorrect", getCouponType(path));
            //assert on sign in page and error messaging exists
            OrderPageTypes curPage = waitForPageType(path, new OrderPageTypes[] { OrderPageTypes.SignIn, OrderPageTypes.TechDif, OrderPageTypes.Payflow, OrderPageTypes.Receipt }, 1000, 500);
            assertCurrentPageIsExpectedType(curPage, new OrderPageTypes[] { OrderPageTypes.SignIn });
            sel.assertLocatorText(
                new String[] { @"//div[@id='loginPageErrorsText']/p[@class='warning']", @"//div[@id='loginPageErrorsText']/p[2]" },
                AugmentedSelenium.Set.All, AugmentedSelenium.Compare.Has,
                new String[] { "Your email address or password is not recognized", "The information you entered does not match an account in our system. Please verify your email address and password and try again. Click below for password assistance or to create an account as a new customer" });
        }



        /// <summary>
        /// bad email format, password
        /// </summary>
        /// <param name="path"></param>
        private void testSignInInvalidCredentialsWrongEmailFormat(OrderPath path) {
            //check if already on sign in page
            if(!isCurrentPageSpecifiedType(sel.GetLocation(), OrderPageTypes.SignIn, path)) {
                sel.openPage(path.URL, true, true);
                //check if opened page is on sign in or sign up page
                if(isCurrentPageSpecifiedType(sel.GetLocation(), OrderPageTypes.SignUp, path)) {
                    sel.Click(sel.getFirstExistingElement(pageTypeTemplates[(int)(OrderPageTypes.SignUp)].RuleValues[5][0]));
                    waitForPageType(path, new OrderPageTypes[] { OrderPageTypes.SignIn, OrderPageTypes.SignUp }, 2500, 300);//doesn't open a new page, just reworks signup/signin
                }
                assertCurrentPageIsExpectedType(new OrderPageTypes[] { OrderPageTypes.SignIn }, path);
            }
            //on sign in so now or exited function, try the account
            signIn("badEmailFormat", "password", getCouponType(path));
            //assert on sign in page and error messaging exists
            OrderPageTypes curPage = waitForPageType(path, new OrderPageTypes[] { OrderPageTypes.SignIn, OrderPageTypes.TechDif, OrderPageTypes.Payflow, OrderPageTypes.Receipt }, 1000, 500);
            assertCurrentPageIsExpectedType(curPage, new OrderPageTypes[] { OrderPageTypes.SignIn });
            sel.assertLocatorText(
                new String[] { @"//div[@id='loginPageErrorsText']/p[@class='warning']", @"//div[@id='loginPageErrorsText']/p[2]" },
                AugmentedSelenium.Set.All, AugmentedSelenium.Compare.Has,
                new String[] { "Your email address or password is not recognized", "The information you entered does not match an account in our system. Please verify your email address and password and try again. Click below for password assistance or to create an account as a new customer" });
        }



        /// <summary>
        /// no email,  password
        /// </summary>
        /// <param name="path"></param>
        private void testSignInInvalidCredentialsNoEmail(OrderPath path) {
            //check if already on sign in page
            if(!isCurrentPageSpecifiedType(sel.GetLocation(), OrderPageTypes.SignIn, path)) {
                sel.openPage(path.URL, true, true);
                //check if opened page is on sign in or sign up page
                if(isCurrentPageSpecifiedType(sel.GetLocation(), OrderPageTypes.SignUp, path)) {
                    sel.Click(sel.getFirstExistingElement(pageTypeTemplates[(int)(OrderPageTypes.SignUp)].RuleValues[5][0]));
                    waitForPageType(path, new OrderPageTypes[] { OrderPageTypes.SignIn, OrderPageTypes.SignUp }, 2500, 300);//doesn't open a new page, just reworks signup/signin
                }
                assertCurrentPageIsExpectedType(new OrderPageTypes[] { OrderPageTypes.SignIn }, path);
            }
            //on sign in so now or exited function, try the account
            signIn("", "password", getCouponType(path));
            //assert on sign in page and error messaging exists
            OrderPageTypes curPage = waitForPageType(path, new OrderPageTypes[] { OrderPageTypes.SignIn, OrderPageTypes.TechDif, OrderPageTypes.Payflow, OrderPageTypes.Receipt }, 1000, 500);
            assertCurrentPageIsExpectedType(curPage, new OrderPageTypes[] { OrderPageTypes.SignIn });
            sel.assertLocatorText(
                new String[] { @"//div[@id='loginPageErrorsText']/p[@class='warning']", @"//div[@id='loginPageErrorsText']/p[2]" },
                AugmentedSelenium.Set.All, AugmentedSelenium.Compare.Has,
                new String[] { "Please correct the error(s) listed below and resubmit your form", "Email Address (or Username) was left blank" });
        }




        /// <summary>
        /// nonexisting account email, password
        /// </summary>
        /// <param name="path"></param>
        private void testSignInInvalidCredentialsNonexistingUser(OrderPath path) {
            //check if already on sign in page
            if(!isCurrentPageSpecifiedType(sel.GetLocation(), OrderPageTypes.SignIn, path)) {
                sel.openPage(path.URL, true, true);
                //check if opened page is on sign in or sign up page
                if(isCurrentPageSpecifiedType(sel.GetLocation(), OrderPageTypes.SignUp, path)) {
                    sel.Click(sel.getFirstExistingElement(pageTypeTemplates[(int)(OrderPageTypes.SignUp)].RuleValues[5][0]));
                    waitForPageType(path, new OrderPageTypes[] { OrderPageTypes.SignIn, OrderPageTypes.SignUp }, 2500, 300);//doesn't open a new page, just reworks signup/signin
                }
                assertCurrentPageIsExpectedType(new OrderPageTypes[] { OrderPageTypes.SignIn }, path);
            }
            //on sign in so now or exited function, try the account
            signIn(@"qa_selenium_nonexisting_account", "password", getCouponType(path));
            //assert on sign in page and error messaging exists
            OrderPageTypes curPage = waitForPageType(path, new OrderPageTypes[] { OrderPageTypes.SignIn, OrderPageTypes.TechDif, OrderPageTypes.Payflow, OrderPageTypes.Receipt }, 1000, 500);
            assertCurrentPageIsExpectedType(curPage, new OrderPageTypes[] { OrderPageTypes.SignIn });
            sel.assertLocatorText(
                new String[] { @"//div[@id='loginPageErrorsText']/p[@class='warning']", @"//div[@id='loginPageErrorsText']/p[2]" },
                AugmentedSelenium.Set.All, AugmentedSelenium.Compare.Has,
                new String[] { "Your email address or password is not recognized", "The information you entered does not match an account in our system. Please verify your email address and password and try again. Click below for password assistance or to create an account as a new customer" });
        }

        #endregion





        #region popup link tests
        /// <summary>
        /// Looks for the Privacy Policy, Terms of Use, Our Guarantee, System Requirements, Offer Terms and other links.
        /// Orderpaths have different behaviors. Some render overlays, others pop up new pages, some only pop in the client app.
        /// Some hide the footer. Some hide some of the links.
        /// The test runs as follows:
        /// Confirm expected links based on the orderpath
        /// Confirm links work
        /// Confirm window or overlay they open contains expected messaging
        /// </summary>
        /// <param name="path"></param>
        /// <returns></returns>
        private void checkOrderPathPageHasPopupLinks(OrderPath path) {
            sel.openPage(path.URL, false, true);
            LinkedList<PopupLink> links = new LinkedList<PopupLink>();
            //ASSERTING LINKS EXIST
            if (path.Skin == OrderPathSkin.S25vcast) {
                try {
                    if (sel.isCssSelectorProperty(new String[]{"p.topnav", "div#footer"}, AugmentedSelenium.Set.All, AugmentedSelenium.Compare.Is, "display", new String[]{"none"}, browser)) {
                        //no links so nothing to test.
                        //could include tests that should fail...
                    } else {
                        sel.assertLocatorText(new String[] { @"//p[@class='topnav']//a[@href='javascript:openCustomerSupport()']" }, AugmentedSelenium.Set.AllSome, AugmentedSelenium.Compare.Has, new String[] { "Customer Support" });//sel.assertTextForElementHasValue(@"//p[@class='topnav']//a[@href='javascript:openCustomerSupport()']", "Customer Support");
                        sel.assertLocatorText(new String[] { @"//p[@class='topnav']//a[@href='javascript:openTermsOfUse()']" }, AugmentedSelenium.Set.AllSome, AugmentedSelenium.Compare.Has, new String[] { "Terms of Use" });//sel.assertTextForElementHasValue(@"//p[@class='topnav']//a[@href='javascript:openTermsOfUse()']", "Terms of Use");
                        sel.assertLocatorText(new String[] { @"//p[@class='topnav']//a[@href='javascript:openPrivacyPolicy()']" }, AugmentedSelenium.Set.AllSome, AugmentedSelenium.Compare.Has, new String[] { "Privacy Policy" });//sel.assertTextForElementHasValue(@"//p[@class='topnav']//a[@href='javascript:openPrivacyPolicy()']", "Privacy Policy");
                        links.AddFirst(new PopupLink(@"//p[@class='topnav']//a[@href='javascript:openCustomerSupport()']", "CustomerSupport", "customer_support_vcast", "customer_support_vcast"));
                        links.AddFirst(new PopupLink(@"//p[@class='topnav']//a[@href='javascript:openTermsOfUse()']", "TermsOfUse", "terms_of_use_vcast", "terms_of_use_vcast"));
                        links.AddFirst(new PopupLink(@"//p[@class='topnav']//a[@href='javascript:openPrivacyPolicy()']", "PrivacyPolicy", "privacy_policy_vcast", "privacy_policy_vcast"));
                    }
                } catch (TestAssertionException e) {
                    e.addLineToDataTop("S25vcast skin. Some of the headNewUser/fields links are missing");
                    throw e;
                }
            } else if (sel.isCssSelectorProperty(new String[]{"div#footer ul"}, AugmentedSelenium.Set.All, AugmentedSelenium.Compare.Is, "display", new String[]{"none"}, browser)) {
                try {
                    sel.assertLocatorText(new String[] { @"//p[@class='topnav']//a[@href='javascript:openCustomerSupport()']" }, AugmentedSelenium.Set.AllSome, AugmentedSelenium.Compare.Has, new String[] { "Customer Support" });//sel.assertTextForElementContainsValue(@"//p[@class='topnav']//a[@href='javascript:openCustomerSupport()']", "Customer Support");//some missing semicolon at the end  
                    sel.assertLocatorText(new String[] { @"//p[@class='topnav']//a[@href='javascript:openPrivacyPolicy()']" }, AugmentedSelenium.Set.AllSome, AugmentedSelenium.Compare.Has, new String[] { "Privacy Policy" });//sel.assertTextForElementHasValue(@"//p[@class='topnav']//a[@href='javascript:openPrivacyPolicy()']", "Privacy Policy");
                    sel.assertLocatorText(new String[] {@"//p[@class='topnav']//a[@href='javascript:openTermsOfUse()']" }, AugmentedSelenium.Set.AllSome, AugmentedSelenium.Compare.Has, new String[] { "Terms of Use" });//sel.assertTextForElementHasValue(@"//p[@class='topnav']//a[@href='javascript:openTermsOfUse()']", "Terms of Use");
                    links.AddFirst(new PopupLink(@"//p[@class='topnav']//a[@href='javascript:openCustomerSupport()']", "CustomerSupport", "customer_support", "customer_support"));
                    links.AddFirst(new PopupLink(@"//p[@class='topnav']//a[@href='javascript:openPrivacyPolicy()']", "PrivacyPolicy", "privacy_policy_rhap", "privacy_policy_rhap"));
                    links.AddFirst(new PopupLink(@"//p[@class='topnav']//a[@href='javascript:openTermsOfUse()']", "TermsOfUse", "terms_of_use_rhap", "terms_of_use_rhap"));
                } catch (TestAssertionException e) {
                    e.addLineToDataTop("Footer hidden. Some of the header links are missing");
                    throw e;
                }
            } else if (path.Skin == OrderPathSkin.Sierra) {
                try {
                    sel.assertLocatorText(new String[] { @"//div[@id='headNewUser']//a[@href='javascript:openSystemRequirements();']" }, AugmentedSelenium.Set.AllSome, AugmentedSelenium.Compare.Has, new String[] { "System Requirements" });//sel.assertTextForElementHasValue(@"//div[@id='headNewUser']//a[@href='javascript:openSystemRequirements();']", "System Requirements");
                    String offerTermsLocator = sel.getFirstExistingElement(new String[] { @"//div[@id=""headNewUser""]//a[@href=""javascript:openOfferTerms('inclientPopupNav','');""]", @"//div[@id='headNewUser']//a[@href='javascript:openOfferTerms();']" });
                    sel.assertLocatorText(new String[] { offerTermsLocator }, AugmentedSelenium.Set.AllSome, AugmentedSelenium.Compare.Has, new String[] { "Offer Terms" });//sel.assertTextForElementHasValue(offerTermsLocator, "Offer Terms");
                    sel.assertLocatorText(new String[] { @"//div[@id='fields']//a[@href='javascript:openPrivacyPolicy();']" }, AugmentedSelenium.Set.AllSome, AugmentedSelenium.Compare.Has, new String[] { "Privacy Policy" });//sel.assertTextForElementHasValue(@"//div[@id='fields']//a[@href='javascript:openPrivacyPolicy();']", "Privacy Policy");
                    links.AddFirst(new PopupLink(@"//div[@id='headNewUser']//a[@href='javascript:openSystemRequirements();']", "SystemRequirements", "system_requirements_rhap", "system_requirements_rhap"));
                    links.AddFirst(new PopupLink(offerTermsLocator, "OfferTerms", "", "Offer Terms"));
                    links.AddFirst(new PopupLink(@"//div[@id='fields']//a[@href='javascript:openPrivacyPolicy();']", "PrivacyPolicy", "privacy_policy_rhap", "privacy_policy_rhap"));
                } catch (TestAssertionException e) {
                    e.addLineToDataTop("Sierra skin. Some of the headNewUser/fields links are missing");
                    throw e;
                }
            } else if (path.Skin == OrderPathSkin.Order2) {
                try {
                    //some Orderpaths have intermediate pages to choose between several options
                    //offer terms and such do not appear until picking the specific path
                    //this means it is valid to not display all the links
                    //to determine if page intends to show just PP link, check for div id = headMenu
                    //if missing then just look for PP link
                    if (sel.IsElementPresent(@"//div[@id='headMenu']")) {
                        sel.assertLocatorText(new String[] { @"//div[@id='headMenu']//a[@href='javascript:openCustomerSupport();']" }, AugmentedSelenium.Set.AllSome, AugmentedSelenium.Compare.Has, new String[] { "Customer Support" });//sel.assertTextForElementHasValue(@"//div[@id='headMenu']//a[@href='javascript:openCustomerSupport();']", "Customer Support");
                        sel.assertLocatorText(new String[] { @"//div[@id='headMenu']//a[@href='javascript:openTermsOfUse();']" }, AugmentedSelenium.Set.AllSome, AugmentedSelenium.Compare.Has, new String[] { "Terms of Use" });//sel.assertTextForElementHasValue(@"//div[@id='headMenu']//a[@href='javascript:openTermsOfUse();']", "Terms of Use");
                        sel.assertLocatorText(new String[] { @"//div[@id='fields']//a[@href='javascript:openPrivacyPolicy();']" }, AugmentedSelenium.Set.AllSome, AugmentedSelenium.Compare.Has, new String[] { "Privacy Policy" });//sel.assertTextForElementContainsValue(@"//div[@id='fields']//a[@href='javascript:openPrivacyPolicy();']", "Privacy Policy");
                        links.AddFirst(new PopupLink(@"//div[@id='headMenu']//a[@href='javascript:openCustomerSupport();']", "CustomerSupport", "customer_support", "customer_support"));
                        links.AddFirst(new PopupLink(@"//div[@id='headMenu']//a[@href='javascript:openTermsOfUse();']", "TermsOfUse", "terms_of_use_rhap", "terms_of_use_rhap"));
                        links.AddFirst(new PopupLink(@"//div[@id='fields']//a[@href='javascript:openPrivacyPolicy();']", "PrivacyPolicy", "privacy_policy_rhap", "privacy_policy_rhap"));
                    } else {
                        sel.assertLocatorText(new String[] { @"//div[@id='fields']//a[@href='javascript:openPrivacyPolicy();']" }, AugmentedSelenium.Set.AllSome, AugmentedSelenium.Compare.Has, new String[] { "Privacy Policy" });//sel.assertTextForElementContainsValue(@"//div[@id='fields']//a[@href='javascript:openPrivacyPolicy();']", "Privacy Policy");
                        links.AddFirst(new PopupLink(@"//div[@id='fields']//a[@href='javascript:openPrivacyPolicy();']", "PrivacyPolicy", "privacy_policy_rhap", "privacy_policy_rhap"));
                    }
                } catch (TestAssertionException e) {
                    e.addLineToDataTop("Order2 skin. Some of the links are missing");
                    throw e;
                }
            } else if (!getCouponType(path).Equals("")) {
                if (path.Skin == OrderPathSkin.RhapRewardsSkin) {//rhap rewards is like table, minus offer terms
                    try {
                        sel.assertLocatorText(new String[] { @"//div[@id='body']//a[@href='javascript:openPrivacyPolicy();']" }, AugmentedSelenium.Set.AllSome, AugmentedSelenium.Compare.Has, new String[] { "Privacy Policy" });//sel.assertTextForElementHasValue(@"//div[@id='body']//a[@href='javascript:openPrivacyPolicy();']", "Privacy Policy");
                        sel.assertLocatorText(new String[] { @"//div[@id='body']//a[@href='javascript:openCustomerSupport();']" }, AugmentedSelenium.Set.AllSome, AugmentedSelenium.Compare.Has, new String[] { "Customer Support" });//sel.assertTextForElementHasValue(@"//div[@id='body']//a[@href='javascript:openCustomerSupport();']", "Customer Support");
                        sel.assertLocatorText(new String[] { @"//div[@id='body']//a[@href='javascript:openTermsOfUse();']" }, AugmentedSelenium.Set.AllSome, AugmentedSelenium.Compare.Has, new String[] { "Terms of Use" });//sel.assertTextForElementHasValue(@"//div[@id='body']//a[@href='javascript:openTermsOfUse();']", "Terms of Use");
                        links.AddFirst(new PopupLink(@"//div[@id='body']//a[@href='javascript:openPrivacyPolicy();']", "PrivacyPolicy", "privacy_policy_rhap", "privacy_policy_rhap"));
                        links.AddFirst(new PopupLink(@"//div[@id='body']//a[@href='javascript:openCustomerSupport();']", "CustomerSupport", "customer_support", "customer_support"));
                        links.AddFirst(new PopupLink(@"//div[@id='body']//a[@href='javascript:openTermsOfUse();']", "TermsOfUse", "terms_of_use_rhap", "terms_of_use_rhap"));
                    } catch (TestAssertionException e) {
                        e.addLineToDataTop("Footer hidden = false; rewards path. Some of the body links are missing");
                        throw e;
                    }
                } else {
                    try {
                        sel.assertLocatorText(new String[] { @"//div[@id='footer']//a[@href='javascript:openPrivacyPolicy();']" }, AugmentedSelenium.Set.AllSome, AugmentedSelenium.Compare.Has, new String[] { "Privacy Policy" });//sel.assertTextForElementHasValue(@"//div[@id='footer']//a[@href='javascript:openPrivacyPolicy();']", "Privacy Policy");
                        sel.assertLocatorText(new String[] { @"//div[@id='footer']//a[@href='javascript:openCustomerSupport();']" }, AugmentedSelenium.Set.AllSome, AugmentedSelenium.Compare.Has, new String[] { "Customer Support", "Customer Service" });//sel.assertTextForElementMatchesAnyValue(@"//div[@id='footer']//a[@href='javascript:openCustomerSupport();']", new String[] { "Customer Support", "Customer Service" });
                        sel.assertLocatorText(new String[] { @"//div[@id='footer']//a[@href='javascript:openTermsOfUse();']" }, AugmentedSelenium.Set.AllSome, AugmentedSelenium.Compare.Has, new String[] { "Terms of Use" });//sel.assertTextForElementHasValue(@"//div[@id='footer']//a[@href='javascript:openTermsOfUse();']", "Terms of Use");
                        //sel.assertTextForElementHasValue(@"//div[@id='footer']//a[@href='javascript:openOurGuarantee();']", "Our Guarantee");
                        links.AddFirst(new PopupLink(@"//div[@id='footer']//a[@href='javascript:openPrivacyPolicy();']", "PrivacyPolicy", "privacy_policy_rhap", "privacy_policy_rhap"));
                        links.AddFirst(new PopupLink(@"//div[@id='footer']//a[@href='javascript:openCustomerSupport();']", "CustomerSupport", "customer_support", "customer_support"));
                        links.AddFirst(new PopupLink(@"//div[@id='footer']//a[@href='javascript:openTermsOfUse();']", "TermsOfUse", "terms_of_use_rhap", "terms_of_use_rhap"));
                        //links.AddFirst(new PopupLink(@"//div[@id='footer']//a[@href='javascript:openOurGuarantee();']", "OurGuarantee", "our_guarantee", "our_guarantee"));
                    } catch (TestAssertionException e) {
                        e.addLineToDataTop("Footer hidden = false; coupon nonrewards path. Some of the footer links are missing");
                        throw e;
                    }
                }
            } else if (sel.IsElementPresent(@"//div[@id='body']/table[1]/tbody[1]/tr[1]/td[1]/a[1]")) {
                try {
                    sel.assertLocatorText(new String[] { @"//div[@id='body']//a[@href='javascript:openPrivacyPolicy();']" }, AugmentedSelenium.Set.AllSome, AugmentedSelenium.Compare.Has, new String[] { "Privacy Policy" });//sel.assertTextForElementHasValue(@"//div[@id='body']//a[@href='javascript:openPrivacyPolicy();']", "Privacy Policy");
                    sel.assertLocatorText(new String[] { @"//div[@id='body']//a[@href='javascript:openTermsOfUse();']" }, AugmentedSelenium.Set.AllSome, AugmentedSelenium.Compare.Has, new String[] { "Terms of Use" });//sel.assertTextForElementHasValue(@"//div[@id='body']//a[@href='javascript:openTermsOfUse();']", "Terms of Use");
                    //sel.assertTextForElementHasValue(@"//div[@id='body']//a[@href='javascript:openOurGuarantee();']", "Our Guarantee");
                    sel.assertLocatorText(new String[] { @"//div[@id='body']//a[@href='javascript:openOfferTerms();']" }, AugmentedSelenium.Set.AllSome, AugmentedSelenium.Compare.Has, new String[] { "Offer Terms", "offer Terms" });//sel.assertTextForElementMatchesAnyValue(@"//div[@id='body']//a[@href='javascript:openOfferTerms();']", new String[] { "Offer Terms", "offer Terms" });
                    links.AddFirst(new PopupLink(@"//div[@id='body']//a[@href='javascript:openPrivacyPolicy();']", "PrivacyPolicy", "privacy_policy_rhap", "privacy_policy_rhap"));
                    links.AddFirst(new PopupLink(@"//div[@id='body']//a[@href='javascript:openTermsOfUse();']", "TermsOfUse", "terms_of_use_rhap", "terms_of_use_rhap"));
                    //links.AddFirst(new PopupLink(@"//div[@id='body']//a[@href='javascript:openOurGuarantee();']", "OurGuarantee", "our_guarantee", "our_guarantee"));
                    links.AddFirst(new PopupLink(@"//div[@id='body']//a[@href='javascript:openOfferTerms();']", "OfferTerms", "", "Offer Terms"));
                } catch (TestAssertionException e) {
                    e.addLineToDataTop("Footer hidden = false; table links = true; Some of the table links are missing");
                    throw e;
                }
            } else {
                try {
                    sel.assertLocatorText(new String[] { @"//div[@id='footer']//a[@href='javascript:openPrivacyPolicy();']" }, AugmentedSelenium.Set.AllSome, AugmentedSelenium.Compare.Has, new String[] { "Privacy Policy" });//sel.assertTextForElementHasValue(@"//div[@id='footer']//a[@href='javascript:openPrivacyPolicy();']", "Privacy Policy");
                    sel.assertLocatorText(new String[] { @"//div[@id='footer']//a[@href='javascript:openTermsOfUse();']" }, AugmentedSelenium.Set.AllSome, AugmentedSelenium.Compare.Has, new String[] { "Terms of Use" });//sel.assertTextForElementHasValue(@"//div[@id='footer']//a[@href='javascript:openTermsOfUse();']", "Terms of Use");
                    //sel.assertTextForElementHasValue(@"//div[@id='footer']//a[@href='javascript:openOurGuarantee();']", "Our Guarantee");
                    sel.assertLocatorText(new String[] { @"//div[@id='footer']//a[@href='javascript:openOfferTerms();']" }, AugmentedSelenium.Set.AllSome, AugmentedSelenium.Compare.Has, new String[] { "Offer Terms" });//sel.assertTextForElementHasValue(@"//div[@id='footer']//a[@href='javascript:openOfferTerms();']", "Offer Terms");
                    links.AddFirst(new PopupLink(@"//div[@id='footer']//a[@href='javascript:openPrivacyPolicy();']", "PrivacyPolicy", "privacy_policy_rhap", "privacy_policy_rhap"));
                    links.AddFirst(new PopupLink(@"//div[@id='footer']//a[@href='javascript:openTermsOfUse();']", "TermsOfUse", "terms_of_use_rhap", "terms_of_use_rhap"));
                    //links.AddFirst(new PopupLink(@"//div[@id='footer']//a[@href='javascript:openOurGuarantee();']", "OurGuarantee", "our_guarantee", "our_guarantee"));
                    links.AddFirst(new PopupLink(@"//div[@id='footer']//a[@href='javascript:openOfferTerms();']", "OfferTerms", "", "Offer Terms"));
                } catch (TestAssertionException e) {
                    e.addLineToDataTop("Footer hidden = false; Some of the footer links are missing");
                    throw e;
                }
            }
            //ASSERTING LINKS WORK
            //existence of DOM: Links.alwaysOpenInWindow determines if some links make an overlay instead of a popout window
            //if list doesnt exist then all pop out by default
            //if item in the list doesn't exist then it is an overlay
            bool linksAlwaysOpenWindow = sel.GetEval(@"var exists; exists = (window.Links.alwaysOpenInWindow == null); exists;").Equals("true");
            bool itemOpensInWindow = false;//since this only matters if alwaysOpenWindow is false, it doesn't need to be right when alwaysOpenWindow is true
            foreach (PopupLink link in links) {
                if (link.inClient) {
                    continue;
                    //may want to add test logic to make sure it doesn't pop a window.
                }
                if (!linksAlwaysOpenWindow) {
                    itemOpensInWindow = doesLinksAlwaysOpenInWindowContainItem(link.DomLinksName);
                }
                sel.Click(link.Locator);
                if (linksAlwaysOpenWindow || itemOpensInWindow) {//POP OUT WINDOW
                    try {
                        sel.WaitForPopUp(link.WindowJSID, "25000");
                        sel.SelectWindow(link.WindowTitle);//different because sel seems weird. This is to handle offers links which has no ID("") but still has a title
                    } catch (Exception e) {
                        String[] IDs = sel.GetAllWindowIds();
                        String[] names = sel.GetAllWindowNames();
                        String[] titles = sel.GetAllWindowTitles();
                        for (int i = 1; i < titles.Length; i++) {
                            sel.SelectWindow(titles[i]);
                            sel.Close();
                        }
                        sel.SelectWindow(null);
                        throw new Exception(link.WindowTitle + " window not found", e);
                    }
                    //ASSERTING POPOUT HAS EXPECTED VALUE
                    try {
                        switch (link.DomLinksName) {//using domLinkName because it only has one value per link, even vcast ones use the same value
                            case "PrivacyPolicy":
                            String ppLocator = sel.getFirstExistingElement(new String[] { "//body/h1", @"//div[@class='texttitle']" });
                            sel.assertLocatorText(new String[] { ppLocator }, AugmentedSelenium.Set.AllSome, AugmentedSelenium.Compare.Has, new String[] { "Rhapsody Privacy Policy", "Privacy Policy" });//sel.assertTextForElementMatchesAnyValue(ppLocator, new String[] { "Rhapsody Privacy Policy", "Privacy Policy" });
                            break;
                            case "TermsOfUse":
                            String touLocator = sel.getFirstExistingElement(new String[] { "//body/h1", @"//h1[@class='pageTitle']" });
                            sel.assertLocatorText(new String[] { touLocator }, AugmentedSelenium.Set.AllSome, AugmentedSelenium.Compare.Has, new String[] { "Rhapsody Service Terms of Use", @"Terms & Conditions" });//sel.assertTextForElementMatchesAnyValue(touLocator, new String[] { "Rhapsody Service Terms of Use", @"Terms & Conditions" });
                            break;
                            case "OurGuarantee":
                            sel.assertLocatorText(new String[] { @"//div[@class='psub popupContent']" }, AugmentedSelenium.Set.AllSome, AugmentedSelenium.Compare.Has, new String[] { "Our Guarantee" });//sel.assertTextForElementHasValue(@"//div[@class='psub popupContent']", "Our Guarantee");
                            break;
                            case "OfferTerms":
                            sel.assertLocatorText(new String[] { @"//div[@class='psub popupContent']" }, AugmentedSelenium.Set.AllSome, AugmentedSelenium.Compare.Has, new String[] { "Offer Terms" });//sel.assertTextForElementContainsValue(@"//div[@class='psub popupContent']", "Offer Terms");//contains, not has
                            break;
                            case "CustomerSupport":
                            String csLocator = sel.getFirstExistingElement(new String[] { @"//div[@id='contentbodytext']", @"//h1[@class='pageTitle']" });
                            sel.assertLocatorText(new String[] { csLocator }, AugmentedSelenium.Set.AllSome, AugmentedSelenium.Compare.Has, new String[] { "Support Topics", "Wireless Support" });//sel.assertTextForElementContainsAnyValue(csLocator, new String[] { "Support Topics", "Wireless Support" });
                            break;
                            case "SystemRequirements":
                            sel.assertLocatorText(new String[] { @"//div[@id='nav']" }, AugmentedSelenium.Set.AllSome, AugmentedSelenium.Compare.Has, new String[] { "SYSTEM REQUIREMENTS:" });//sel.assertTextForElementContainsValue(@"//div[@id='nav']", "SYSTEM REQUIREMENTS:");//contains, not has
                            break;

                            default:
                            break;
                        }

                    } catch (TestAssertionException te) {
                        te.addLineToDataTop(link.WindowTitle + " messaging not found");
                        throw te;
                    } finally {
                        sel.Close();
                        sel.SelectWindow(null);
                    }
                } else { //ASSERTING OVERLAY HAS EXPECTED VALUE
                    String opaqueElementLocator = "";
                    String closeOverlayLocator = "";
                    switch (link.DomLinksName) {
                        case "PrivacyPolicy":

                        break;
                        case "TermsOfUse":

                        break;
                        case "OurGuarantee":
                        opaqueElementLocator = @"//div[@id='our_guarantee_window']";
                        closeOverlayLocator = @"//a[@id='close_item_container_our_guarantee']";
                        break;
                        case "OfferTerms":
                        opaqueElementLocator = @"//div[@id='null_window']";
                        closeOverlayLocator = @"//a[@id='close_item_container_null']";
                        break;
                        case "CustomerSupport":

                        break;
                        case "SystemRequirements":

                        break;

                        default:
                        break;
                    }

                    try {
                        sel.assertLocatorAttribute(new String[] { opaqueElementLocator }, AugmentedSelenium.Set.AllSome, AugmentedSelenium.Compare.Has, "style", new String[] { "opacity: 1;" });//sel.assertAttributeForElementContainsValue(opaqueElementLocator, "style", "opacity: 1;");
                        sel.Click(closeOverlayLocator);
                        sel.assertLocatorAttribute(new String[] { opaqueElementLocator }, AugmentedSelenium.Set.AllSome, AugmentedSelenium.Compare.Has, "style", new String[] { "opacity: 0;" });//sel.assertAttributeForElementContainsValue(opaqueElementLocator, "style", "opacity: 0;");
                    } catch (TestAssertionException te) {
                        te.addLineToDataTop(link.WindowTitle + " overlay functionality has failed");
                        throw te;
                    }
                }
            }
        }
        #endregion
        #endregion




        #region UTILITY ORDERPATH TEST FUNCTIONS
        /// <summary>
        /// Resets the 'used for trial offer' flag retrieved by RealStoreRCService.isConsumerEligibleForFreeTrial.
        /// This reset is done to a specific account, which has an active subscription using the CC in question.
        /// Resetting this flag for that account will allow new trial purchases with that CC, even if other accounts
        /// have that CC for some active or inactive subscription.
        /// 
        /// This makes it easy to quickly renew the CC just before a test proper, and removes dependency on other
        /// tests to clean up after themselves. So, DON'T BREAK THE DUMMY ACCOUNT WITH THE ACTIVE SUBSCRIPTION USING THE CC.
        /// </summary>
        /// <returns></returns>
        private void renewCC() {
            String accountName;
            String ccNumber;
            String webToolURL;

            if (!isProductionSubscriptionEnvironement(environment)) {
                accountName = @"qa_seleniumRenewInternalCC@rhapsody.lan";
                ccNumber = "4556474670906442";
                webToolURL = @"http://cs-int-1201.sea2.rhapsody.com:8180/cstool/index.html";
            } else {
                accountName = "";
                ccNumber    = "";
                webToolURL  = "";
            }

            try {
                sel.openPage( webToolURL, true, true );
                sel.waitForLocatorExistence(new String[] { @"//input[@value='Login']", @"//input[@name='new_email']" }, AugmentedSelenium.Set.AllSome, 25000, 200);
                if (sel.isLocatorExistence(new String[] { @"//input[@value='Login']" }, AugmentedSelenium.Set.All)) {
                    sel.Click(@"//input[@value='Login']");//this will handle the case where the page is opened past the sign in page
                }
                sel.waitForLocatorExistence(new String[] {@"//input[@name='new_email']" }, AugmentedSelenium.Set.All, 25000, 200);
                sel.Type(@"//input[@name='new_email']", accountName);
                sel.Click(@"//input[@value='Search']");//ambiguous but shouldn't matter
                //sometimes will skip sign in page, then on search click, go back to it(very annoying design), so adding an additional login logic check
                sel.waitForLocatorExistence(new String[] {@"//input[@value='Login']", @"//form[@name='formQueryResult']/table[2]/tbody[1]/tr[4]/td[2]/li[5]/font[1]/a[1]"},AugmentedSelenium.Set.AllSome, 25000, 200);
                if ( sel.isLocatorExistence( new String[] { @"//input[@value='Login']" }, AugmentedSelenium.Set.All ) ) {
                    sel.Click( @"//input[@value='Login']" );//this will handle the case where the page is opened past the sign in page
                    sel.waitForLocatorExistence( new String[] { @"//form[@name='formQueryResult']/table[2]/tbody[1]/tr[4]/td[2]/li[5]/font[1]/a[1]" }, AugmentedSelenium.Set.All, 25000, 200 );
                }
                sel.Click(@"//form[@name='formQueryResult']/table[2]/tbody[1]/tr[4]/td[2]/li[5]/font[1]/a[1]");
                sel.waitForLocatorExistence(new String[] { @"//input[@type='radio' and @value='ALL']" }, AugmentedSelenium.Set.All, 25000, 200);
                sel.Click(@"//input[@type='radio' and @value='ALL']");
                sel.Click(@"//input[@value='Clear Free Trial']");
                sel.waitForText(new String[] {       @"//center[1]/span[@class='text label']", @"//form[@id='j_id2']/table[1]/tbody[1]/tr[1]/td[1]" }, AugmentedSelenium.Set.AllSome, AugmentedSelenium.Compare.Has, new String[] { "Free Trial was cleared successfully for this customer's payment methods.", "Could not find any existing payment methods on free trial for this customer." }, 25000, 200);
                sel.assertLocatorText(new String[] { @"//center[1]/span[@class='text label']", @"//form[@id='j_id2']/table[1]/tbody[1]/tr[1]/td[1]" }, AugmentedSelenium.Set.AllSome, AugmentedSelenium.Compare.Has, new String[] { "Free Trial was cleared successfully for this customer's payment methods.", "Could not find any existing payment methods on free trial for this customer." });
            }catch(SeleniumException se){
                TestAssertionException t = new TestAssertionException(se);
                t.addLineToDataTop(se.Message);
                t.addLineToDataTop("CC renewal failed");
                throw t;
            }catch(TestAssertionException te){
                te.addLineToDataTop("CC renewal failed");
                throw te;
            }
        }



        /// <summary>
        /// checks the dom Links.alwaysOpenInWindow string[] for a given string. Returns whether or not it exists
        /// </summary>
        /// <param name="item"></param>
        /// <returns></returns>
        private bool doesLinksAlwaysOpenInWindowContainItem(String item) {
            String js = @"var exists = false; for (var i in window.Links.alwaysOpenInWindow) {if (window.Links.alwaysOpenInWindow[i] == '" + item + "') { exists = true; } } exists;";
            return sel.GetEval(js).Equals("true");
            //var exists = false;
            //for (var i in Links.alwaysOpenInWindow) {
            //    if (Links.alwaysOpenInWindow[i] == " + item + ") {
            //        exists = true; 
            //    }
            //}
            //exists;
        }


        /*
        /// <summary>
        /// This opens a page and waits for it to load and verifies location is the URL specified
        /// </summary>
        /// <param name="url">The full location</param>
        /// <param name="reopenEvenIfOnPage">A flag that controls logic to determine whether or not to call the open command if the current location is the same as the URL specified</param>
        /// <param name="ignoreQueryParams">A flag that controls logic to determine whether or not to ignore everything after the path of the current URL when comparing it to the supplied URL</param>
        private void openPage(String url, bool reopenEvenIfOnPage, bool ignoreQueryParams) {
            if (reopenEvenIfOnPage) {
                sel.Open(url);
                sel.WaitForPageToLoad("25000");
                sel.assertPresentLocation(url, true);
            } else {
                if (sel.openIfNotAt(url, ignoreQueryParams)) {
                    sel.WaitForPageToLoad("25000");
                    sel.assertPresentLocation(url, true);
                }
            }
        }*/


        private String clickHomePageBuyButton() {
            sel.waitForLocatorExistence(new String[] { @"//div[@class='homepageModuleFeaturedCopy']//a[@class='album']" }, AugmentedSelenium.Set.All, 25000, 200);//sel.tryWaitForElementToExist(@"//div[@class='homepageModuleFeaturedCopy']//a[@class='album']", 25000, 200);
            String albumName = sel.GetText(@"//div[@class='homepageModuleFeaturedCopy']//a[@class='album']");
            sel.waitForLocatorExistence(new String[] { @"//a[@class='cartButton cartButtonAddsmall']" }, AugmentedSelenium.Set.All, 25000, 200);//sel.tryWaitForElementToExist(@"//a[@class='cartButton cartButtonAddsmall']", 25000, 200);
            sel.Click(@"//a[@class='cartButton cartButtonAddsmall']");
            sel.waitForLocatorExistence(new String[] { @"//div[@class='orangeActionButtonSm']/a[1]" }, AugmentedSelenium.Set.All, 25000, 200);//sel.tryWaitForElementToExist(@"//div[@class='orangeActionButtonSm']/a[1]", 25000, 200);
            sel.Click(@"//div[@class='orangeActionButtonSm']/a[1]");
            sel.WaitForPageToLoad("25000");
            return albumName;
        }


        private void clickCheckoutButton() {
            sel.waitForLocatorExistence(new String[] { @"//div[@class='orangeActionButton']/a[1]" }, AugmentedSelenium.Set.All, 25000, 200);//sel.tryWaitForElementToExist(@"//div[@class='orangeActionButton']/a[1]", 25000, 200);     
            sel.Click(@"//div[@class='orangeActionButton']/a[1]");
            sel.WaitForPageToLoad("25000");
        }

        
        /// <summary>
        /// Attempts to sign in with specified credentials from an order path sign in page. 
        /// Verification(negative or positive) of the result is not in the scope of this function
        /// </summary>
        /// <param name="userName"></param>
        /// <param name="password"></param>
        private void signIn(String userName, String password, String coupon="") {
            sel.assertLocatorExistence(pageTypeTemplates[(int)(OrderPageTypes.SignIn)].RuleValues[0][0], AugmentedSelenium.Set.AllSome);//email input field
            sel.assertLocatorExistence(pageTypeTemplates[(int)(OrderPageTypes.SignIn)].RuleValues[1][0], AugmentedSelenium.Set.AllSome);//password input field
            String couponTextField = sel.getFirstExistingElement( pageTypeTemplates[(int)(OrderPageTypes.SignIn)].RuleValues[3][0] );//optional coupon field
            if(!coupon.Equals("")) {
                sel.assertLocatorExistence(new String[]{couponTextField} , AugmentedSelenium.Set.AllSome);
            }
            sel.assertLocatorExistence(pageTypeTemplates[(int)(OrderPageTypes.SignIn)].RuleValues[2][0], AugmentedSelenium.Set.AllSome);//submit button
            //determine the locators that actually do exist for email, password, and submit
            try {
                sel.Type(sel.getFirstExistingElement(pageTypeTemplates[(int)(OrderPageTypes.SignIn)].RuleValues[0][0]), userName);
                sel.Type(sel.getFirstExistingElement(pageTypeTemplates[(int)(OrderPageTypes.SignIn)].RuleValues[1][0]), password);
                if(!coupon.Equals("")) {
                    sel.Type(couponTextField, coupon);
                }
                sel.Click(sel.getFirstExistingElement(pageTypeTemplates[(int)(OrderPageTypes.SignIn)].RuleValues[2][0]));
            } catch(SeleniumException se) {
                throw new TestAssertionException("Could not enter account credentials or submit", se);
            }
            sel.WaitForPageToLoad("25000");
        }


        /// <summary>
        /// Ensures on sign up/in page, tries typing email, password,confirmPassword and optional credentials.
        /// Some after page load waiting is done for certain JS files as a way of stalling until submit will work.
        /// Last, the submit button is located and clicked, and a pageLoad wait ends the function.
        /// </summary>
        /// <param name="email"></param>
        /// <param name="password0"></param>
        /// <param name="password1"></param>
        /// <param name="coupon"></param>
        /// <param name="path"></param>
        private void inputOrderPathAccount(String email, String password0, String password1, String coupon, OrderPath path, out String username) {
            //watch for sign up pages
            OrderPageTypes curPageType = waitForPageType(path, new OrderPageTypes[] { OrderPageTypes.SignUp, OrderPageTypes.SignIn, OrderPageTypes.TechDif, OrderPageTypes.SessionExpired }, 25000, 200);
            if (curPageType == OrderPageTypes.SignIn && sel.IsElementPresent(@"//input[@id='newUserType']")) {
                sel.Click(@"//input[@id='newUserType']");
                if (waitForPageType(path, new OrderPageTypes[] { OrderPageTypes.SignUp, OrderPageTypes.SignIn, OrderPageTypes.TechDif, OrderPageTypes.SessionExpired }, 5000, 200) != OrderPageTypes.SignUp) {
                    throw new TestAssertionException("Could not recognize sign up page after selecting new user from sign in page");
                }
            } else if (curPageType != OrderPageTypes.SignUp) {
                throw new TestAssertionException("Could not recognize sign up page or an acceptable sign in page with a sign up link. Instead on: "+curPageType.ToString());
            }

            sel.Type(pageTypeTemplates[(int)(OrderPageTypes.SignUp)].RuleValues[4][0][0], email);
            sel.Type(pageTypeTemplates[(int)(OrderPageTypes.SignUp)].RuleValues[4][0][1], password0);
            sel.Type(pageTypeTemplates[(int)(OrderPageTypes.SignUp)].RuleValues[4][0][2], password1);
            username = email;

            if (sel.isLocatorExistence(pageTypeTemplates[(int)(OrderPageTypes.SignUp)].RuleValues[7][0], AugmentedSelenium.Set.AllSome)) {
                //TODO find better solution to blackberry username no 'display: none;' height workaround hack
                if(!isBlackberrySignUpWithNoHeightUserNameField(path)){
                    int cutoff = Math.Max(0, Math.Min(20, email.IndexOf("@")));
                    username = email.Substring(0, cutoff).Replace(".", "_");
                    sel.Type( sel.getFirstExistingElement( pageTypeTemplates[(int)(OrderPageTypes.SignUp)].RuleValues[7][0]), username);
                }
            }

            String couponTextField = sel.getFirstExistingElement( pageTypeTemplates[(int)(OrderPageTypes.SignUp)].RuleValues[4][1] );
            if( (couponTextField != null)){
                sel.Type(couponTextField, coupon);
            }

            sel.tryWaitForJSFunctionToExist("s_dr", 25000, 200);
            sel.tryWaitForJSFunctionToExist("loginButtonClick", 25000, 200);
            
            String buttonLocator = sel.getFirstExistingElement( pageTypeTemplates[(int)(OrderPageTypes.SignUp)].RuleValues[4][2] );
            if (buttonLocator == null) {
                sel.assertLocatorExistence(pageTypeTemplates[(int)(OrderPageTypes.SignUp)].RuleValues[4][2], AugmentedSelenium.Set.AllSome);//force code to error out with useful messaging
            }
            sel.Click(buttonLocator);
            sel.WaitForPageToLoad("25000");
            if (path.SignUpOverlay) {
                sel.SubmitForm( pageTypeTemplates[(int)(OrderPageTypes.SignUp)].RuleValues[3][0][0] );
                sel.WaitForPageToLoad("25000");
            }
        }





        /// <summary>
        /// This tries to enter values into expected elements. Then the expected submit button is clicked and selenium is instructed
        /// to wait for the following page to load in most cases. If the elements do not exist, selenium exceptions are thrown and 
        /// attempt fails. Any page verification/loading should be done before the function call.
        /// </summary>
        /// <param name="fName"></param>
        /// <param name="lName"></param>
        /// <param name="selCCType"></param>
        /// <param name="CCType"></param>
        /// <param name="CCNum"></param>
        /// <param name="selMonth"></param>
        /// <param name="month"></param>
        /// <param name="selYear"></param>
        /// <param name="year"></param>
        /// <param name="phoneNum"></param>
        /// <param name="billAddr"></param>
        /// <param name="city"></param>
        /// <param name="selState"></param>
        /// <param name="state"></param>
        /// <param name="zipcode"></param>
        /// <param name="checkConfirmCheckbox"></param>
        /// <exception cref="SeleniumException">Throws SeleniumException if any payflow input element does not exist when function attempts to enter value to it</exception>
        /// <exception cref="TestAssertionException">Throws TestAssertionException for some of the input elements if they don't exist. Most are not tested however.</exception>
        private void inputCCInfo(String fName, String lName, bool selCCType, String CCType, String CCNum, bool selMonth, String month, bool selYear, String year, String phoneNum, String billAddr, String city, bool selState, String state, String zipcode, bool checkConfirmCheckbox) {
            /*
            sel.waitForLocatorExistence(new String[] { 
                @"//input[@id='firstName']", 
                @"//input[@id='lastName']", 
                @"//select[@id='paymentSubtypeMenu']", 
                @"//input[@id='paymentAccountNumber']", 
                @"//select[@id='expMonth']",
                @"//select[@id='expYear']",
                @"//input[@id='billingAddress']",
                @"//input[@id='city']",
                @"//select[@id='addressStateMenu']",
                @"//input[@id='addressPostalCodeText']",
                }, AugmentedSelenium.Set.All, 25000, 200);
            sel.assertLocatorExistence(new String[] { @"//input[@id='firstName']" }, AugmentedSelenium.Set.AllSome);*/
            sel.Type(@"//input[@id='firstName']", fName);
            sel.Type(@"//input[@id='lastName']", lName);
            if (selCCType) {
                if(sel.getFirstExistingElement(pageTypeTemplates[(int)(OrderPageTypes.Payflow)].RuleValues[1][0] ).Equals(pageTypeTemplates[(int)(OrderPageTypes.Payflow)].RuleValues[1][0][1])) {
                    sel.Click(pageTypeTemplates[(int)(OrderPageTypes.Payflow)].RuleValues[1][0][1]);
                }else{
                    sel.Select(pageTypeTemplates[(int)(OrderPageTypes.Payflow)].RuleValues[1][0][0], CCType);
                }
            }
            sel.Type(@"//input[@id='paymentAccountNumber']", CCNum);
            if (selMonth) {
                sel.Select(@"//select[@id='expMonth']", month);
            }
            if (selYear) {
                sel.Select(@"//select[@id='expYear']", year);
            }
            sel.Type(@"//input[@id='billingAddress']", billAddr);
            sel.Type(@"//input[@id='city']", city);
            if (selState) {
                sel.Select(@"//select[@id='addressStateMenu']", state);
            }
            sel.Type(@"//input[@id='addressPostalCodeText']", zipcode);
            if (sel.IsElementPresent(@"//input[@id='addressPhoneNumberText']")) {
                sel.Type(@"//input[@id='addressPhoneNumberText']", phoneNum);
            }
            if(isAgreementRequiredState(state)){
                sel.assertLocatorExistence(new String[] { @"//div[@id='termsText' and @style='display: block;']//input[@id='agreeTermsCheckBox']" }, AugmentedSelenium.Set.All);
                bool isAlreadyChecked = sel.IsChecked(@"//div[@id='termsText' and @style='display: block;']//input[@id='agreeTermsCheckBox']");
                
                if (checkConfirmCheckbox) {
                    if (!isAlreadyChecked) {
                        sel.Click(@"//div[@id='termsText' and @style='display: block;']//input[@id='agreeTermsCheckBox']");
                    }
                } else  {
                    if (isAlreadyChecked) {
                        sel.Click(@"//div[@id='termsText' and @style='display: block;']//input[@id='agreeTermsCheckBox']");
                    }
                }
            }
            sel.Click(sel.getFirstExistingElement(new String[] { @"//input[@id='payflowSubmit']", @"//input[@id='payflowSubmit2']" }));
            if ( !isAgreementRequiredState( state ) || ( checkConfirmCheckbox && isAgreementRequiredState( state ) ) ) {//conditional is being explicit to explain the cases, could be simplified
                sel.WaitForPageToLoad("25000");
            }
        }


        /// <summary>
        /// Verifies an existing account can sign in on rotw
        /// </summary>
        /// <param name="email"></param>
        /// <param name="password"></param>
        private void assertSignInOnROTW(String email, String password) {
            try {
                sel.openPage(rotwSigninFullURI.AbsoluteUri, false, true);
                sel.Type(@"//input[@id='username']", email);
                sel.Type(@"//input[@id='password']", password);
                sel.Click(@"//input[@id='login-submit']");//TODO error with the browserbot.submit for the form: formElement.submit not a function. So, using .Click instead, find how to fix the submit error
                sel.WaitForPageToLoad("25000");
                sel.assertPresentLocation(rotwURI.AbsoluteUri, true);
            } catch(SeleniumException se) {
                TestAssertionException t = new TestAssertionException(se);
                t.addLineToDataTop(se.Message);
                t.addLineToDataTop("Sign in on "+rotwSigninFullURI.AbsoluteUri + " could not be verified");
                throw t;
            } catch(TestAssertionException te) {
                te.addLineToDataTop("Sign in on "+rotwSigninFullURI.AbsoluteUri + " could not be verified");
                throw te;
            }
            try {
                sel.assertLocatorAttribute(new String[] { @"//a[@id='login-user']" }, AugmentedSelenium.Set.All, AugmentedSelenium.Compare.Is, "title", new String[] { email });
            } catch(TestAssertionException te) {
                te.addLineToDataTop("Sign in on "+rotwSigninFullURI.AbsoluteUri + " failed for email: "+ email);
                throw te;
            }
        }
        #endregion




        #region UTILITIES
        /// <summary>
        /// Sets any miscellaneous browser settings. This is the first thign that is called the moment the browser is opened.
        /// For FF, this includes setting signon.rememberSignons to true
        /// </summary>
        private void initializeBrowserConfig(){
            switch (browser) {
                case SeleniumServer.Browser.Firefox:
                sel.openPage("about:config",false,false);//may not be necessary to be on the config page to change its values with the following js 
                sel.GetEval(
                    @"var prefs = Components.classes[""@mozilla.org/preferences-service;1""].getService(Components.interfaces.nsIPrefService).getBranch("""");
                      prefs.setBoolPref(""signon.rememberSignons"", true); 
                      var returnBool = prefs.getBoolPref(""signon.rememberSignons""); 
                      returnBool;"
                );
                    //open about:config
                    //run the following js:
                /*
                 * 
                 * var prefs = Components.classes ["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefService).getBranch("");
                 * prefs.setBoolPref("signon.rememberSignons", true);
                 * 
                 */

                break;

            }




            sel.openBlankPage(browser);
        }


        private bool isAgreementRequiredState( String state ) {
            foreach ( String s in Enum.GetNames( typeof(AgreementRequiredStates) ) ) {
                if ( s.CompareTo( state ) == 0 ) {
                    return true;
                }
            }
            return false;
        }


        /// <summary>
        /// This function checks the height of the username field, which is the only way to 
        /// determine if a blackberry path uses it for sign up, since the 'display: none;'
        /// attribute value is not present
        /// </summary>
        /// <param name="path"></param>
        /// <returns></returns>
        private bool isBlackberrySignUpWithNoHeightUserNameField(OrderPath path) {
            return (path.URL.Contains("blackberry") &&
                sel.GetElementHeight(sel.getFirstExistingElement(pageTypeTemplates[(int)(OrderPageTypes.SignUp)].RuleValues[7][0])).Equals(0));
        }


        /// <summary>
        /// should pull this logic into the environment build up stuff and the rest into the OrderPath Struct logic later
        /// </summary>
        /// <param name="path"></param>
        /// <returns></returns>
        private String getCouponType(OrderPath path) {
            //rhapmp3coupons       - track credit
            //rhaprewardsskin      - track credit
            //rhapprepaiddownloads - track credit
            //rhapprepaidsubskin   - account sub credit
            //INT vs Prod

            if(isProductionSubscriptionEnvironement(environment)){
                return "";
            }else{
                switch (path.Skin) {
                    case OrderPathSkin.RhapMP3CouponsSkin:
                    return "TRACK-INT-QA";
                    case OrderPathSkin.RhapPrepaidDownloadSkin:
                    return "TRACK-INT-QA";
                    case OrderPathSkin.RhapRewardsSkin:
                    return "TRACK-INT-QA";
                    case OrderPathSkin.RhapPrepaidSubscriptionSkin:
                    return "RU2M-INT-QA";
                    case OrderPathSkin.rhapCostcoMP3CouponSkin:
                    return "TRACK-INT-QA";
                    case OrderPathSkin.rhapCostcoRewardsSkin:
                    return "TRACK-INT-QA";
                    case OrderPathSkin.napsterMyCokeRewardsMP3CouponSkin:
                    return "TRACK-INT-QA";
                    default:
                    return "";
                }

            }
        }




        private void buildStaticPaths() {
            R25PATH.CategoryTab = "url-rhapsody";
            R25PATH.Name = "r25Other";
            R25PATH.URL = orderURI.AbsoluteUri + @"rhapsody/free";
            R25PATH.Trial =  false;
            R25PATH.Active = true;
            R25PATH.Skin = (OrderPathSkin)Enum.Parse(typeof(OrderPathSkin), "S1rhapsody25", true);
            R25PATH.Post = false;
            R25PATH.SignUpOverlay = false;
        

        }


        /// <summary>
        /// run this after creating the environmentURIs. This will then use those
        /// to define the expected url for the template(or part of it in the case of a template url that depends on orderpath)
        /// </summary>
        private void buildOrderpathPageTemplates() {
            pageTypeTemplates = new OrderPathPage[Enum.GetValues(typeof(OrderPageTypes)).Length];
            //Unrecognized = 0, SignIn, SignUp, DifferedOffer, Payflow, Receipt, TechDif, AlreadyMember, SessionExpired, TrialExpired, UpsellOffer

            pageTypeTemplates[(int)(OrderPageTypes.SignIn)] = new OrderPathPage(new Uri(orderURI.AbsoluteUri.Substring(0, orderURI.AbsoluteUri.Length - orderURI.AbsolutePath.Length)), OrderPageTypes.SignIn);
            pageTypeTemplates[(int)(OrderPageTypes.SignIn)].RuleValues.Add(new String[1][] { 
                new String[]{@"//div[@id='fieldUsernameEmail' and (not(@style='display: none;'))]//input[@id='userNameExisting']", 
                @"//li[@class='formfield']/input[@id='userNameExisting']", 
                @"//tr[@id='fieldUsernameEmail' and (not(@style='display: none;'))]//input[@id='userNameExisting']" }
            });
            pageTypeTemplates[(int)(OrderPageTypes.SignIn)].Rules.Add(delegate() { return sel.isLocatorExistence(pageTypeTemplates[(int)(OrderPageTypes.SignIn)].RuleValues[0][0], AugmentedSelenium.Set.AllSome); });
            pageTypeTemplates[(int)(OrderPageTypes.SignIn)].RuleValues.Add(new String[1][] { new String[] { @"//input[@id='password']" } });
            pageTypeTemplates[(int)(OrderPageTypes.SignIn)].Rules.Add(delegate() { return sel.isLocatorExistence(pageTypeTemplates[(int)(OrderPageTypes.SignIn)].RuleValues[1][0], AugmentedSelenium.Set.All); });
            pageTypeTemplates[(int)(OrderPageTypes.SignIn)].RuleValues.Add(new String[1][] { 
                new String[] { @"//div[@id='signinButton' and (not(@style='display: none;'))]/input[@id='signin']", 
                @"//li[@class='buttonholder']/button[@class='newuserbutton signinbutton']", 
                @"//div[@id='loginFormSigninButton' and (not(contains(@style,'display: none;')))]/input[@id='signinButton']",
                @"//div[@id='loginFormButtons']/input[@id='signinButton' and (not(contains(@style,'display: none;')))]",
                @"//div[@id='fixedfooter']/input[@class='continue' and @type='submit' and @alt='Continue']",
                @"//div[@id='buttonSection']/input[@id='signinButton' and (not(contains(@style,'display: none;')))]"} 
            });
            pageTypeTemplates[(int)(OrderPageTypes.SignIn)].Rules.Add(delegate() { return sel.isLocatorExistence(pageTypeTemplates[(int)(OrderPageTypes.SignIn)].RuleValues[2][0], AugmentedSelenium.Set.AllSome); });
            pageTypeTemplates[(int)(OrderPageTypes.SignIn)].RuleValues.Add(new String[1][] { 
                new String[] { @"//input[@id='couponCode']",  @"//input[@id='loginFormFieldCoupon']" }
            });


            pageTypeTemplates[(int)(OrderPageTypes.SignUp)] = new OrderPathPage(new Uri(orderURI.AbsoluteUri.Substring(0, orderURI.AbsoluteUri.Length - orderURI.AbsolutePath.Length)), OrderPageTypes.SignUp);
            pageTypeTemplates[(int)(OrderPageTypes.SignUp)].RuleValues.Add(new String[1][] { new String[] { 
                @"//td[@class='fieldText' and @style='padding-bottom:15px;']/input[@id='email']", 
                //@"//div[@id='fieldEmailAddress' and (not(@style) or @style='display:block;')]/input[@id='email']", 
                @"//li[@class='formfield']/input[@id='email']", 
                @"//div[@class='form']/ul[1]/li[@class='label']", 
                @"//tr[@id='fieldEmailAddress' and (not(@style) or (@style='display:table-row;' or @style='display:table-row;'))]//input[@id='email']",
                //@"//div[@id='fieldEmailAddress' and (not(@style) or @style='display:block;')]/div[@class='paddingT10']/input[@id='email']",
                @"//div[@id='fieldEmailAddress' and (not(contains(@style,'display: none;')))]//input[@id='email']"} });
            pageTypeTemplates[(int)(OrderPageTypes.SignUp)].Rules.Add(delegate() {return sel.isLocatorExistence(pageTypeTemplates[(int)(OrderPageTypes.SignUp)].RuleValues[0][0], AugmentedSelenium.Set.AllSome);});
            pageTypeTemplates[(int)(OrderPageTypes.SignUp)].Rules.Add(delegate() { return sel.isLocatorExistence(new String[] { @"//input[@id='password']", @"//input[@id='mdn']" }, AugmentedSelenium.Set.AllSome); });
            pageTypeTemplates[(int)(OrderPageTypes.SignUp)].RuleValues.Add(new String[1][] { new String[] { 
                @"//td[@class='fieldText' and @style='padding-bottom:10px;']/input[@id='confirmPassword']", 
                //@"//div[@id='fieldConfirmPassword' and (not(@style) or @style='display:block;')]/input[@id='confirmPassword']", 
                @"//li[@class='newuser formfield nopad' and (@style='display: list-item;' or @style='display:block;')]/input[@id='confirmPassword']", 
                @"//tr[@id='fieldConfirmPassword' and @style='display:table-row;']/input[@id='confirmPassword']", 
                @"//li[@class='buttonholder']/button[@id='GetPassword']",
                @"//tr[@id='fieldConfirmPassword' and (not(@style) or @style='display:table-row;')]//input[@id='confirmPassword']", 
                //@"//div[@id='fieldConfirmPassword' and (not(@style) or @style='display:block;')]/div[@class='paddingT10']/input[@id='confirmPassword']",
                @"//div[@id='fieldConfirmPassword' and (not(contains(@style,'display: none;')))]//input[@id='confirmPassword']"}});
            pageTypeTemplates[(int)(OrderPageTypes.SignUp)].Rules.Add(delegate() {return sel.isLocatorExistence(pageTypeTemplates[(int)(OrderPageTypes.SignUp)].RuleValues[1][0], AugmentedSelenium.Set.AllSome); });
            pageTypeTemplates[(int)(OrderPageTypes.SignUp)].RuleValues.Add(new String[1][] { new String[] {@"//div[@id='loginFormContinueButton' and (@style='padding-top:30px;' or @style='padding-top:15px; display:block;')]/input[@id='continueButton']",  
                @"//div[@id='continueButton' and (not(@style) or @style='display:block;')]/input[@id='continue']", 
                @"//li[@class='buttonholder']/button[@class='newuserbutton']", 
                @"//li[@class='buttonholder']/button[@id='HavePassword']", 
                @"//div[@id='loginFormButtons']/input[@id='continueButton' and (not(@style) or @style='display:inline;')]",
                @"//div[@id='fixedfooter']/input[@id='continueButton']",
                @"//div[@id='buttonSection']/input[@id='continueButton' and (not(contains(@style,'display: none;')))]"} });
            // TODO fill out proper username field locator set and coupon field locator set that avoids display none and such, and try to solve blackberry path that has no display: none;
            pageTypeTemplates[(int)(OrderPageTypes.SignUp)].Rules.Add(delegate() {return sel.isLocatorExistence(pageTypeTemplates[(int)(OrderPageTypes.SignUp)].RuleValues[2][0], AugmentedSelenium.Set.AllSome); });
            pageTypeTemplates[(int)(OrderPageTypes.SignUp)].RuleValues.Add(new String[1][] { new String[] { @"//form[@id='flowCommonFormFields']" } });
            pageTypeTemplates[(int)(OrderPageTypes.SignUp)].RuleValues.Add(new String[3][] { 
                new String[] { @"//input[@id='email']", @"//input[@id='password']", @"//input[@id='confirmPassword']",@"//input[@id='userNameNew']", }, 
                new String[] { @"//input[@id='couponCode']",  @"//input[@id='loginFormFieldCoupon']" }, 
                new String[] { @"//button[@class='newuserbutton']", @"//input[@id='continueButton']", @"//input[@id='continue']" } });
            pageTypeTemplates[(int)(OrderPageTypes.SignUp)].RuleValues.Add(new String[1][] { 
                new String[] { @"//a[@name='existing']", 
                @"//div[@id='formTitleNewUser' and (not(contains(@style,'display: none;')))]//a[@class='med_link']", 
                @"//div[@id='fieldUserType' and (not(contains(@style,'display: none;')))]/input[@id='existUserType']",
                @"//input[@alt='Sign in.']",
                @"//div[@id='existingUserTypeButton' and (not(contains(@style,'display: none;')))]//a[@class='lg_link']",
                @"//div[@id='existingUserTypeButton' and (not(contains(@style,'display: none;')))]//a[@class='signin-or-register-link']"} 
            });
            pageTypeTemplates[(int)( OrderPageTypes.SignUp )].RuleValues.Add( new String[1][] { 
                new String[] { @"//input[@id='couponCode']",  @"//input[@id='loginFormFieldCoupon']" } 
            });
            pageTypeTemplates[(int)( OrderPageTypes.SignUp )].RuleValues.Add( new String[1][] { 
                new String[] { @"//ul[@class='usernameholder' and (not(contains(@style, 'display: none;')))]//input[@id='userNameNew']",
                @"//tr[@id='fieldUsername' and (not(contains(@style, 'display: none;')))]//input[@id='userNameNew']",
                @"//div[@id='fieldUsername' and (not(contains(@style, 'display: none;')))]//input[@id='userNameNew']",
                } 
            } );
            

            pageTypeTemplates[(int)(OrderPageTypes.DifferedOffer)] = new OrderPathPage(new Uri(orderURI.AbsoluteUri.Substring(0, orderURI.AbsoluteUri.Length - orderURI.AbsolutePath.Length)), OrderPageTypes.DifferedOffer);
            pageTypeTemplates[(int)(OrderPageTypes.DifferedOffer)].Rules.Add(delegate() { return sel.isLocatorExistence(new String[] { @"//input[@id='selectedOfferId']", @"//input[@id='selectedOfferId1']" }, AugmentedSelenium.Set.Some); });
            pageTypeTemplates[(int)(OrderPageTypes.DifferedOffer)].RuleValues.Add(new String[1][] { new String[] { @"//form[@id='flowCommonFormFields']" } });
            pageTypeTemplates[(int)(OrderPageTypes.DifferedOffer)].Rules.Add(delegate() { return sel.isLocatorExistence(new String[] { pageTypeTemplates[(int)(OrderPageTypes.DifferedOffer)].RuleValues[0][0][0] }, AugmentedSelenium.Set.All); });
            pageTypeTemplates[(int)(OrderPageTypes.DifferedOffer)].Rules.Add(delegate() { return sel.isLocatorExistence(new String[] { @"//input[@id='email']", @"//div[@id='signinButton']", @"//div[@class='receipt']", @"//input[@id='firstName']" }, AugmentedSelenium.Set.None); });
            //pageTypeTemplates[(int)(OrderPageTypes.DifferedOffer)].Rules.Add(delegate() { return sel.isLocatorExistence(new String[] { @"//input[@id='selectedOfferId1']", @"//input[@id='continueButton']" }, AugmentedSelenium.Set.All); });
            //pageTypeTemplates[(int)(OrderPageTypes.DifferedOffer)].Rules.Add(delegate() { return sel.isLocatorExistence(new String[] { @"//input[@id='email']", @"//div[@id='signinButton']", @"//div[@class='receipt']", @"//input[@id='firstName']" }, AugmentedSelenium.Set.None); });


            pageTypeTemplates[(int)(OrderPageTypes.Payflow)] = new OrderPathPage(new Uri(payflowURI.AbsoluteUri, UriKind.Absolute), OrderPageTypes.Payflow);
            pageTypeTemplates[(int)(OrderPageTypes.Payflow)].RuleValues.Add(new String[1][]{new String[] { 
                @"//input[@id='firstName']", @"//input[@id='lastName']", @"//input[@id='paymentAccountNumber']", @"//select[@id='expMonth']", 
                @"//select[@id='expYear']", @"//input[@id='billingAddress']", @"//input[@id='city']", @"//select[@id='addressStateMenu']", 
                @"//input[@id='addressPostalCodeText']"}});
            pageTypeTemplates[(int)(OrderPageTypes.Payflow)].RuleValues.Add(new String[1][]{new String[] { 
                @"//select[@id='paymentSubtypeMenu']", @"//input[@id='paymentType']"}});
            pageTypeTemplates[(int)(OrderPageTypes.Payflow)].Rules.Add(delegate() {return sel.isLocatorExistence(pageTypeTemplates[(int)(OrderPageTypes.Payflow)].RuleValues[0][0], AugmentedSelenium.Set.All);});
            pageTypeTemplates[(int)(OrderPageTypes.Payflow)].Rules.Add(delegate() { return sel.isLocatorExistence(pageTypeTemplates[(int)(OrderPageTypes.Payflow)].RuleValues[1][0], AugmentedSelenium.Set.AllSome); });
            pageTypeTemplates[(int)(OrderPageTypes.Payflow)].Rules.Add(delegate() { return sel.isLocatorExistence(new String[] { @"//input[@id='payflowSubmit']", @"//input[@id='payflowSubmit2']" }, AugmentedSelenium.Set.AllSome); });


            pageTypeTemplates[(int)(OrderPageTypes.Receipt)] = new OrderPathPage(new Uri(orderURI.AbsoluteUri.Substring(0, orderURI.AbsoluteUri.Length - orderURI.AbsolutePath.Length)), OrderPageTypes.Receipt);
            //all receipt page types
            pageTypeTemplates[(int)(OrderPageTypes.Receipt)].RuleValues.Add(
                new String[2][]{
                    new String[]{@"//div[@id='body']/div[@class='receipt']/h1[1]", 
                    @"//div[@id='body']/div[@id='content']/div[@id='pageTitle' and (@style='margin-top: 2px;' or @style='margin-top: 5px;')]",
                    @"//div[@id='body']/div[@id='content']/div[@id='pageTitle']/div[@id='pageTitleExistingUser']/font[1]",
                    @"//div[@id='body']/div[@id='content']/div[@id='headText']/div[@class='pSub']",
                    @"//div[@id='wrapper']/div[@id='content']/h1[1]",
                    @"//div[@id='content']/div[@id='contentHeadline']",
                    @"//div[@id='receipt-container']/h1[@id='receipt-header']"}, 
                    new String[]{"Rhapsody Premier: Free Trial", 
                    "Rhapsody Premier: Sign Up", 
                    "Rhapsody Premier Plus: Free Trial", 
                    "Rhapsody Premier Plus: Sign Up", 
                    "Rhapsody To Go: Free Trial", 
                    "Rhapsody To Go: Sign Up", 
                    "Rhapsody Unlimited: Sign Up",
                    "Rhapsody Unlimited: Sign In",
                    "Rhapsody Unlimited: Free Trial",
                    "Rhapsody: Free Trial", 
                    "Rhapsody: Sign Up",
                    "Coupon Redemption",
                    "Credit Redemption",
                    "Rhapsody Unlimited + 10 MP3s: Sign Up",
                    "Rhapsody Unlimited + 10 MP3s: Sign In",
                    "Rhapsody MP3 Account",
                    "Rhapsody Pre-Paid Membership",
                    "Thank you!",
                    "Welcome to Rhapsody",
                    "Thank you for joining Rhapsody!",
                    "Thanks",
                    "Start shopping for your MP3's"}});
            pageTypeTemplates[(int)(OrderPageTypes.Receipt)].Rules.Add(delegate() { return sel.isLocatorText(pageTypeTemplates[(int)(OrderPageTypes.Receipt)].RuleValues[0][0], AugmentedSelenium.Set.AllSome, AugmentedSelenium.Compare.Has, pageTypeTemplates[(int)(OrderPageTypes.Receipt)].RuleValues[0][1]); });
            pageTypeTemplates[(int)(OrderPageTypes.Receipt)].RuleValues.Add(
                new String[2][]{
                    new String[] { 
                    @"//div[@id='body']/div[@class='receipt']/div[@class='column']/h3[1]", 
                    @"//div[@id='body']/div[@class='receipt']/div[@class='headTextBody noline']/h2[1]", 
                    @"//div[@id='body']/div[@id='content']/div[@id='contentHeadline' and (@style='padding-bottom: 3px; margin-bottom: 15px;' or @style='padding-bottom: 5px; margin-bottom: 15px;')]", 
                    @"//div[@id='body']/div[@id='content']/div[@id='pageTitle']/div[@id='pageTitleExistingUser']",
                    @"//div[@id='wrapper']/div[@id='content']/h1[1]",
                    @"//div[@id='body']/div[@class='receipt']/h1[1]",
                    @"//div[@id='body']/div[@id='content']/div[@id='headText']/div[@class='pSub']",
                    @"//div[@id='body']/div[@id='content']/div[@id='pageTitle']/div[@id='pageTitleExistingUser']",
                    @"//div[@id='receipt-container']/div[@id='main-section']/div[@id='textSection']/h2[1]",
                    @"//div[@id='receipt-container']/div[@id='text-section']"},
                    new String[] { 
                    "Thanks for joining Rhapsody",
                    "Listen to Music Online",
                    "Start shopping for your favorites",
                    "Thank you",
                    "Thank You",
                    "Your account has been updated",
                    "Welcome to Rhapsody",
                    "How do you want to start listening?",
                    "You've successfully added credits to your account."}});
            pageTypeTemplates[(int)(OrderPageTypes.Receipt)].Rules.Add(delegate() { return sel.isLocatorText(pageTypeTemplates[(int)(OrderPageTypes.Receipt)].RuleValues[1][0], AugmentedSelenium.Set.AllSome, AugmentedSelenium.Compare.Has, pageTypeTemplates[(int)(OrderPageTypes.Receipt)].RuleValues[1][1]); });
            //all possible messaging for trial offer receipt pages
            pageTypeTemplates[(int)(OrderPageTypes.Receipt)].RuleValues.Add(
                new String[1][]{ 
                    new String[]{"Rhapsody Premier: Free Trial", 
                    "Rhapsody Premier Plus: Free Trial", 
                    "Rhapsody To Go: Free Trial", 
                    "Rhapsody: Free Trial",
                    "Rhapsody Unlimited: Free Trial",
                    "Thank you",
                    "Thanks",
                    "Start shopping for your MP3's"}});
            //all possible messaging for non-trial offer receipt pages
            pageTypeTemplates[(int)(OrderPageTypes.Receipt)].RuleValues.Add(
                new String[1][]{
                    new String[]{"Rhapsody Premier: Sign Up", 
                    "Rhapsody Premier Plus: Sign Up", 
                    "Rhapsody To Go: Sign Up", 
                    "Rhapsody Unlimited: Sign Up",
                    "Rhapsody Unlimited: Sign In",
                    "Rhapsody: Sign Up",
                    "Rhapsody Unlimited + 10 MP3s: Sign Up",
                    "Rhapsody Unlimited + 10 MP3s: Sign In",
                    "Thank you",
                    "Rhapsody MP3 Account",
                    "Welcome to Rhapsody"}});
            //all possible messaging for coupon offer receipt pages
            pageTypeTemplates[(int)(OrderPageTypes.Receipt)].RuleValues.Add(                
                new String[1][]{
                    new String[]{"Credit Redemption:",
                        "Your Account has been updated",
                        "Thank You",
                        "Your account has been updated",
                        "Thanks for joining Rhapsody!",
                        "Rhapsody Pre-Paid Membership:",
                        "Thanks",
                        "Start shopping for your MP3's"}});
            //all possible messaging for non-coupon offer receipt pages
            pageTypeTemplates[(int)(OrderPageTypes.Receipt)].RuleValues.Add(
                new String[1][]{                    
                    new String[]{"Rhapsody Premier: Free Trial", 
                    "Rhapsody Premier: Sign Up", 
                    "Rhapsody Premier Plus: Free Trial", 
                    "Rhapsody Premier Plus: Sign Up", 
                    "Rhapsody To Go: Free Trial", 
                    "Rhapsody To Go: Sign Up", 
                    "Rhapsody Unlimited: Sign Up",
                    "Rhapsody Unlimited: Sign In",
                    "Rhapsody Unlimited: Free Trial",
                    "Thank you",
                    "Rhapsody: Free Trial", 
                    "Rhapsody: Sign Up",
                    "Rhapsody MP3 Account",
                    "Rhapsody Unlimited + 10 MP3s: Sign Up"}});

            
            pageTypeTemplates[(int)(OrderPageTypes.TechDif)] = new OrderPathPage(new Uri(orderURI.AbsoluteUri.Substring(0, orderURI.AbsoluteUri.Length - orderURI.AbsolutePath.Length)), /*rotwURI.AbsoluteUri + @"/-techdiff", UriKind.Absolute)*/ OrderPageTypes.TechDif);
            pageTypeTemplates[(int)(OrderPageTypes.TechDif)].Rules.Add(delegate() { return sel.isLocatorText(new String[] { @"//div[@id='CSTitle']", @"//div[@id='content']/div[@id='pageTitle']" }, AugmentedSelenium.Set.AllSome, AugmentedSelenium.Compare.Has, new String[] { "Technical Difficulties" }); });


            pageTypeTemplates[(int)(OrderPageTypes.AlreadyMember)] = new OrderPathPage(new Uri(orderURI.AbsoluteUri.Substring(0, orderURI.AbsoluteUri.Length - orderURI.AbsolutePath.Length)), OrderPageTypes.AlreadyMember);
            pageTypeTemplates[(int)(OrderPageTypes.AlreadyMember)].RuleValues.Add(new String[2][] {
                    new String[] { 
                    @"//div[@id='body']/div[@id='content']/div[@class='formheadwrapper']/div[@class='formhead']/h2[1]", 
                    @"//div[@id='body']/div[@id='content']/h1[1]", 
                    @""}, 
                    new String[] { 
                    "You are already a member" }});
            pageTypeTemplates[(int)(OrderPageTypes.AlreadyMember)].Rules.Add(delegate() { return sel.isLocatorText(pageTypeTemplates[(int)(OrderPageTypes.AlreadyMember)].RuleValues[0][0], AugmentedSelenium.Set.AllSome, AugmentedSelenium.Compare.Has, pageTypeTemplates[(int)(OrderPageTypes.AlreadyMember)].RuleValues[0][1]); });


            pageTypeTemplates[(int)(OrderPageTypes.SessionExpired)] = new OrderPathPage(new Uri(sessExpireFullURI.AbsoluteUri, UriKind.Absolute), OrderPageTypes.SessionExpired);
            pageTypeTemplates[(int)(OrderPageTypes.SessionExpired)].Rules.Add(delegate() { return sel.isLocatorText(new String[] { @"//div[@id='CSTitle']", @"//title" }, AugmentedSelenium.Set.All, AugmentedSelenium.Compare.Has, new String[] { "Session expired", "Session Expired" }); });


            pageTypeTemplates[(int)(OrderPageTypes.TrialExpired)] = new OrderPathPage(new Uri(orderURI.AbsoluteUri.Substring(0, orderURI.AbsoluteUri.Length - orderURI.AbsolutePath.Length)), OrderPageTypes.TrialExpired);
            pageTypeTemplates[(int)(OrderPageTypes.TrialExpired)].Rules.Add(delegate() { return sel.isLocatorExistence(new String[] { @"//input[@id='continueButton']", @"//div[@class='buttonholder']/a[@class='continue']" }, AugmentedSelenium.Set.AllSome); });
            pageTypeTemplates[(int)(OrderPageTypes.TrialExpired)].RuleValues.Add(new String[2][]{
                new String[]{@"//div[@id='content']/div[@class='column']/p[1]", 
                        @"//form[@id='flowCommonFormFields']/div[1]", 
                        @"//form[@id='flowCommonFormFields']/div[2]"}, 
                new String[]{@"Therefore you're not eligible for another free trial or extension.", 
                        @"Therefore, you are not eligible for this free trial offer."}});
            pageTypeTemplates[(int)(OrderPageTypes.TrialExpired)].Rules.Add(delegate() { return sel.isLocatorText(pageTypeTemplates[(int)(OrderPageTypes.TrialExpired)].RuleValues[0][0], AugmentedSelenium.Set.Some, AugmentedSelenium.Compare.Has, pageTypeTemplates[(int)(OrderPageTypes.TrialExpired)].RuleValues[0][1]); });
            //pageTypeTemplates[(int)(OrderPageTypes.TrialExpired)].Rules.Add(delegate() { return sel.isLocatorExistence(new String[] { @"//input[@id='selectedOfferId1']", @"//input[@id='email']", @"//div[@id='signinButton']", @"//div[@class='receipt']", @"//input[@id='firstName']" }, AugmentedSelenium.Set.None); });

            /*
             * trialExpired : https://realstore.rhapsody.com/rhapsody/...   (no /realstore/ part of the relative path for INT/prod) for local, it is the same as the other path urls 
             */
            pageTypeTemplates[(int)(OrderPageTypes.UpsellOffer)] = new OrderPathPage(new Uri(orderURI.AbsoluteUri.Substring(0, orderURI.AbsoluteUri.Length - orderURI.AbsolutePath.Length)), OrderPageTypes.UpsellOffer);
            pageTypeTemplates[(int)(OrderPageTypes.UpsellOffer)].RuleValues.Add(new String[1][]{
                new String[]{@"//div[@id='body']/div[@id='content']/form[@id='flowCommonFormFields']/div[@id='submitButtons']/ul[1]/li[@class='last']/a[@id='getRhapOnly']", 
                @"//div[@id='body']/div[@id='content']/form[@id='flowCommonFormFields']/div[@id='submitButtons']/ul[1]//input[@id='addOfferButton']"}});
            pageTypeTemplates[(int)(OrderPageTypes.UpsellOffer)].Rules.Add(delegate() { return sel.isLocatorExistence(pageTypeTemplates[(int)(OrderPageTypes.UpsellOffer)].RuleValues[0][0], AugmentedSelenium.Set.All); });


            pageTypeTemplates[(int)( OrderPageTypes.UnavailableMembership )] = new OrderPathPage( new Uri( orderURI.AbsoluteUri.Substring( 0, orderURI.AbsoluteUri.Length - orderURI.AbsolutePath.Length ) ), OrderPageTypes.UnavailableMembership );
            pageTypeTemplates[(int)( OrderPageTypes.UnavailableMembership )].RuleValues.Add( new String[2][]{
                new String[]{@"//div[@id='content']/div[@id='CSTitle']" },
                new String[] { "Sorry, we are not able to provide this offer for your cobrand" }
            } );
            pageTypeTemplates[(int)( OrderPageTypes.UnavailableMembership )].Rules.Add( delegate() { return sel.isLocatorText( pageTypeTemplates[(int)( OrderPageTypes.UnavailableMembership )].RuleValues[0][0], AugmentedSelenium.Set.All, AugmentedSelenium.Compare.Has, pageTypeTemplates[(int)( OrderPageTypes.UnavailableMembership )].RuleValues[0][1] ); } );
            pageTypeTemplates[(int)( OrderPageTypes.UnavailableMembership )].RuleValues.Add( new String[2][]{
                new String[]{@"//div[@id='content']/div[@id='CSBody']" },
                new String[] {"We are not able to provide this offer for your cobrand"}
            } );
            pageTypeTemplates[(int)( OrderPageTypes.UnavailableMembership )].Rules.Add( delegate() { return sel.isLocatorText( pageTypeTemplates[(int)( OrderPageTypes.UnavailableMembership )].RuleValues[1][0], AugmentedSelenium.Set.All, AugmentedSelenium.Compare.Has, pageTypeTemplates[(int)( OrderPageTypes.UnavailableMembership )].RuleValues[1][1] ); } );
            pageTypeTemplates[(int)( OrderPageTypes.UnavailableMembership )].RuleValues.Add( new String[1][]{
                new String[]{@"//div[@id='content']/div[@id='CSBody']/a[1]"
                }} );
            pageTypeTemplates[(int)( OrderPageTypes.UnavailableMembership )].Rules.Add( delegate() { return sel.isLocatorExistence( pageTypeTemplates[(int)( OrderPageTypes.UnavailableMembership )].RuleValues[2][0], AugmentedSelenium.Set.All ); } );
            
        }




        /// <summary>
        /// Additional version, letting user specify which types to look for before failing
        /// Another benefit is the order of page types tested, allowing for mostly likely
        /// to least likely which cuts costs
        /// </summary>
        /// <param name="currentPath"></param>
        /// <param name="typeSubsetToSearch">An array containing single values from OrderPathTypes. If more than one value is added per enum, it will break</param>
        /// <param name="timeout"></param>
        /// <param name="interval"></param>
        /// <returns></returns>
        private TestRunner.OrderPageTypes waitForPageType(OrderPath currentPath, OrderPageTypes[] typeSubsetToSearch, int timeout, int interval) {
            DateTime endTime = DateTime.Now.AddMilliseconds((double)timeout);
            //System.Diagnostics.Debug.WriteLine("Expected end time: " + endTime.ToString("yyyy/MM/dd HH:mm:ss.fff"));
            while (DateTime.Compare(endTime, DateTime.Now) > 0) {
                String currentLocation = sel.GetLocation();
                foreach (OrderPageTypes pageType in typeSubsetToSearch) {
                    if (pageType == OrderPageTypes.Unrecognized) {
                        continue;//this prevents use of the unrecognized type(since it doesn't even make sense in this context). Not clean, but could be worse
                    }
                    if (isCurrentPageSpecifiedType(currentLocation, pageType, currentPath)) {
                        return pageType;
                    }
                }
                timeout -= System.Math.Abs(interval);
                System.Threading.Thread.Sleep(interval);
            }
            return TestRunner.OrderPageTypes.Unrecognized;
        }


        /// <summary>
        /// Checks that the current location matches the pageTemplate url
        /// or pageTemplate url non relative part + relative part of currentPath url
        /// Only urls that depend on current orderpath change. The rest are constant
        /// at least per environment so they hold the expected url already. Final 
        /// modifications are included for paths that can change based on flow(such as 
        /// trailing / for pages after payflow)
        /// </summary>
        /// <param name="currentLocation"></param>
        /// <param name="pageTemplate"></param>
        /// <param name="currentPath"></param>
        /// <returns></returns>
        private bool isCurrentLocationMatchPage(String currentLocation, OrderPageTypes pageType, OrderPath currentPath) {

            //orderPathURI = currentPageType.StaticURL.Host + (CurrentPath.URL - CurrentPath.URL.Host) 
            //IE:  host in static template URL + the relative URL part for the specific order path
            //this makes sure OP url is on the right track. We have to assume the rest of the url is what we expect(particularly for the path)
            //for the templates that aren't dynamic, they wont use this rebuilt url to compare with anyhow, so this should work
            Uri dynamicURL = new Uri(currentPath.URL, UriKind.Absolute);
            Uri orderPathUri = new Uri(dynamicURL.AbsoluteUri.Replace(dynamicURL.Host, pageTypeTemplates[(int)pageType].StaticURL.Host), UriKind.Absolute);
            Uri expectedURL;

            //template url:
            //environment defines the fieldVars for the base url + hard coded relative urls when necessary for particular urls that don't change based on orderpath
            //the ones that do should only have the base url, and let the orderpath.url.relative fill in the rest
            //for these types, that means they should only be
            //https://realstore.int.rhapsody.com/
            //http://127.0.0.1:8080/
            //these values can be obtained by using the environment defined fieldVars - their relative paths(not sure about the slashes though)
            /*
             * URI scheme: http
             * URI userinfo: (null)
             * URI host: 127.0.0.1
             * Is host an IP address?: yes
             * URI port: 8080
             * URI path: /test1/test2/test3/test4
             * URI query: queryTest=test1&test2=test3
             * URI fragment: (null)
             * "http://127.0.0.1:8080/test1/test2/test3/test4?queryTest=test1&test2=test3"
             */

            Uri currentLocationURL = new Uri(currentLocation, UriKind.Absolute);
            //String parsedCurrentLocation = currentLocationURL.AbsoluteUri.Substring(0, currentLocationURL.AbsoluteUri.Length - currentLocationURL.Query.Length);
            String parsedCurrentLocation = currentLocationURL.AbsoluteUri;
            if(currentLocationURL.Query.Length > 0) {
                parsedCurrentLocation = parsedCurrentLocation.Replace(currentLocationURL.Query, "");
            }
            if(currentLocationURL.Fragment.Length > 0) {
                parsedCurrentLocation = parsedCurrentLocation.Replace(currentLocationURL.Fragment, "");
            }
            
            if (parsedCurrentLocation.LastIndexOf(";jsessionid=") != -1) {//if it exists, remove it and everything after it(should only be the jsession value at this point)
                parsedCurrentLocation = parsedCurrentLocation.Remove(parsedCurrentLocation.LastIndexOf(";jsessionid="));
            }

            switch(pageType) {
                case OrderPageTypes.AlreadyMember:
                    expectedURL = new Uri(orderPathUri.AbsoluteUri.Replace(orderPathUri.AbsolutePath, @"/order"+ orderPathUri.AbsolutePath), UriKind.Absolute);
                    break;
                case OrderPageTypes.DifferedOffer:
                    expectedURL = new Uri(orderPathUri.AbsoluteUri, UriKind.Absolute);
                    break;
                case OrderPageTypes.Payflow:
                    expectedURL = pageTypeTemplates[(int)pageType].StaticURL;//can be two pages depending if user has input bad credentials
                    return (parsedCurrentLocation.Equals(expectedURL.AbsoluteUri) || 
                        parsedCurrentLocation.Equals(expectedURL.AbsoluteUri + @"/") || 
                        parsedCurrentLocation.Equals(expectedURL.AbsoluteUri +@"/index.xhtml"));
                case OrderPageTypes.Receipt:
                    expectedURL = new Uri(orderPathUri.AbsoluteUri.Replace(orderPathUri.AbsolutePath, @"/order" + orderPathUri.AbsolutePath) + @"/", UriKind.Absolute);//all pages after the payflow page come back with an extra / at the end
                    return parsedCurrentLocation.Equals(expectedURL.AbsoluteUri) ||
                    parsedCurrentLocation.Equals(expectedURL.AbsoluteUri.Replace(@"/order/", @"/")) ||
                    parsedCurrentLocation.Equals(expectedURL.AbsoluteUri.Remove(expectedURL.AbsoluteUri.LastIndexOf(@"/"), 1)) ||//receipt pages that skip payflow(no subscription) have no trailing /
                    parsedCurrentLocation.Equals(expectedURL.AbsoluteUri.Substring(0, expectedURL.AbsoluteUri.Length - 1));
                case OrderPageTypes.SessionExpired:
                    expectedURL = pageTypeTemplates[(int)pageType].StaticURL;
                    //no change, the value is determined fully by environment determined URI since it is so inconsistent
                    break;
                case OrderPageTypes.SignIn:
                    expectedURL = new Uri(orderPathUri.AbsoluteUri, UriKind.Absolute);
                    return parsedCurrentLocation.Equals(expectedURL.AbsoluteUri) ||
                    parsedCurrentLocation.Equals(expectedURL.AbsoluteUri.Replace(orderPathUri.AbsolutePath, @"/order"+ orderPathUri.AbsolutePath));
                    //some paths sign in/up link opens a new page(blackberry paths), and /order is added to the URL
                case OrderPageTypes.SignUp:
                    expectedURL = new Uri(orderPathUri.AbsoluteUri, UriKind.Absolute);
                    break;
                case OrderPageTypes.TechDif:
                    expectedURL = new Uri(orderPathUri.AbsoluteUri.Replace(orderPathUri.AbsolutePath, @"/order" + orderPathUri.AbsolutePath), UriKind.Absolute);// pageTypeTemplates[(int)pageType].StaticURL;
                    return parsedCurrentLocation.Equals(expectedURL.AbsoluteUri) ||
                    parsedCurrentLocation.Equals(expectedURL.AbsoluteUri + @"/"); //for past payflow,  ending '/'
                case OrderPageTypes.TrialExpired:
                    expectedURL = new Uri(orderPathUri.AbsoluteUri, UriKind.Absolute);
                    
                    //expectedURL = new Uri( orderPathUri.AbsoluteUri.Replace( orderPathUri.AbsolutePath, @"/order" + orderPathUri.AbsolutePath ), UriKind.Absolute );
                    return parsedCurrentLocation.Equals(expectedURL.AbsoluteUri) || //signin can go to trialexpired depending on account, so can have no '/'
                    parsedCurrentLocation.Equals(expectedURL.AbsoluteUri.Replace(expectedURL.AbsolutePath, @"/order" + expectedURL.AbsolutePath)) ||
                    parsedCurrentLocation.Equals(expectedURL.AbsoluteUri.Replace(expectedURL.AbsolutePath, @"/order" + expectedURL.AbsolutePath) + @"/") ||
                    parsedCurrentLocation.Equals(expectedURL.AbsoluteUri + @"/"); //for past payflow,  ending '/'
                case OrderPageTypes.UpsellOffer:
                    expectedURL = new Uri(orderPathUri.AbsoluteUri + @"/", UriKind.Absolute);//all pages after the payflow page come back with an extra / at the end
                    break;
                case OrderPageTypes.UnavailableMembership:
                    expectedURL = new Uri( orderPathUri.AbsoluteUri.Replace( orderPathUri.AbsolutePath, @"/order" + orderPathUri.AbsolutePath ), UriKind.Absolute );
                    break;
                default:
                    expectedURL = new Uri("");
                    break;
            }


            return parsedCurrentLocation.Equals(expectedURL.AbsoluteUri); 
        }


        /// <summary>
        /// Asserts that the page type passed to the function matches one of the accepted types specified.
        /// If it doesn't, an exception is thrown that lists expected page types, type passed, and current URL location.
        /// </summary>
        /// <param name="specifiedPageType"></param>
        /// <param name="acceptedPageTypes"></param>
        private void assertCurrentPageIsExpectedType(OrderPageTypes specifiedPageType, OrderPageTypes[] acceptedPageTypes) {
            foreach (OrderPageTypes t in acceptedPageTypes) {
                if (t == specifiedPageType) {
                    return;
                }
            }
            TestAssertionException e = new TestAssertionException(TestAssertionException.AssertionTypeEnum.AtLocation);
            e.addLineToDataBottom("Current page type is " + specifiedPageType.ToString());
            e.addLineToDataBottom("Expected page types:");
            foreach (OrderPageTypes p in acceptedPageTypes) {
                e.addLineToDataBottom(p.ToString());
            }
            try {
                e.addLineToDataBottom("Current location: "+ sel.GetLocation());
            } catch (Exception) { }
            throw e;
        }


        /// <summary>
        /// Asserts that the current page type found matches one of the accepted types specified.
        /// If it doesn't, an exception is thrown that lists expected page types, and current URL location.
        /// This function does not determine what the current page type is, if it is not one specified.
        /// Slight differences in logic between this and the other overload can have meaningful differences
        /// in behavior. For example, this retests the current page for each type it matches against. This
        /// allows for more up to date tests, but it is slower because it doesn't just compare page types,
        /// but checks the actual browser page itself.
        /// </summary>
        /// <param name="specifiedPageType"></param>
        /// <param name="path"></param>
        /// <exception cref="SeleniumException"></exception>
        private void assertCurrentPageIsExpectedType( OrderPageTypes[] acceptedPageTypes, OrderPath path) {
            foreach(OrderPageTypes t in acceptedPageTypes) {
                if(isCurrentPageSpecifiedType(sel.GetLocation(), t, path)) {
                    return;
                }
            }
            TestAssertionException e = new TestAssertionException(TestAssertionException.AssertionTypeEnum.AtLocation);
            e.addLineToDataBottom("Current page is not one of the expected page types:");
            foreach(OrderPageTypes p in acceptedPageTypes) {
                e.addLineToDataBottom(p.ToString());
            }
            try {
                e.addLineToDataBottom("Current location: "+ sel.GetLocation());
            } catch(Exception) { }
            throw e;
        }



        /// <summary>
        /// Matches the current selenium browser location and locators against expected page template url
        /// and selector sets. These sets are separated by expectation(all exist, at least one, none and also text, or just locator existence).
        /// The first failure breaks the logic to keep checks down.
        /// </summary>
        /// <param name="pageTemplate"></param>
        /// <param name="currentPath"></param>
        /// <returns></returns>
        private bool isCurrentPageSpecifiedType(String currentLocation, OrderPageTypes pageType, OrderPath currentPath) {
            if (!isCurrentLocationMatchPage(currentLocation, pageType, currentPath)) {
                return false;
            }

            foreach (DifferedComparisonDelegate differedCompareRule in pageTypeTemplates[(int)pageType].Rules) {
                DifferedComparisonDelegate curDelgate = differedCompareRule;
                if (!curDelgate()) {
                    return false;
                }
            }

            return true;
        }




        /// <summary>
        /// Asserts that at least one locator/text pair will be found on the current page
        /// from a set of locators and text strings. The set of text messages to be looked
        /// for is determined by which receipt page is present.
        /// </summary>
        /// <param name="couponOffer"></param>
        /// <param name="trialOffer"></param>
        /// <param name="noPayflowOffer"></param>
        private void assertReceiptPageMessaging(bool couponOffer, bool trialOffer, bool noPayflowOffer) {
            HashSet<String> couponOrNonMessaging = new HashSet<string>();
            HashSet<String> trialOrNonMessaging = new HashSet<string>();
            HashSet<String> expectedMessaging = new HashSet<string>();
            if (noPayflowOffer) {
                if (couponOffer) {
                    //expectedMessaging = couponSet 4
                    foreach (String s in pageTypeTemplates[(int)(OrderPageTypes.Receipt)].RuleValues[4][0]) {
                        expectedMessaging.Add(s);
                    }
                } else {
                    //expectedMessaging = non-couponSet 5
                    foreach (String s in pageTypeTemplates[(int)(OrderPageTypes.Receipt)].RuleValues[5][0]) {
                        expectedMessaging.Add(s);
                    }
                }
            } else {
                if (couponOffer) {
                    //couponOrNonMessaging = couponSet 4
                    foreach (String s in pageTypeTemplates[(int)(OrderPageTypes.Receipt)].RuleValues[4][0]) {
                        couponOrNonMessaging.Add(s);
                    }
                } else {
                    //couponOrNonMessaging = non-couponSet 5
                    foreach (String s in pageTypeTemplates[(int)(OrderPageTypes.Receipt)].RuleValues[5][0]) {
                        couponOrNonMessaging.Add(s);
                    }
                }
                if (trialOffer) {
                    //trialOrNonMessaging = trialSet 2
                    foreach (String s in pageTypeTemplates[(int)(OrderPageTypes.Receipt)].RuleValues[2][0]) {
                        trialOrNonMessaging.Add(s);
                    }
                } else {
                    //trialOrNonMessaging = non-trialSet 3
                    foreach (String s in pageTypeTemplates[(int)(OrderPageTypes.Receipt)].RuleValues[3][0]) {
                        trialOrNonMessaging.Add(s);
                    }
                }
                //expectedMessaging = intersect of trialOrNonMessaging and couponOrNonMessaging
                expectedMessaging.UnionWith(couponOrNonMessaging);
                expectedMessaging.IntersectWith(trialOrNonMessaging);
            }
            
            String[] expectedSuccessMessaging = new String[expectedMessaging.Count];
            expectedMessaging.CopyTo(expectedSuccessMessaging);

            try {
                //use receipt template locators found in first ruleValue and specific set messaging found in the subsequent ruleValues 
                sel.assertLocatorText(pageTypeTemplates[(int)(OrderPageTypes.Receipt)].RuleValues[0][0],
                    AugmentedSelenium.Set.AllSome,
                    AugmentedSelenium.Compare.Has,
                    expectedSuccessMessaging);
            } catch (TestAssertionException e) {
                e.addLineToDataTop("No payflow: " + noPayflowOffer.ToString() + ", coupon offer: " + couponOffer.ToString() + ", trial offer: " + trialOffer.ToString());
                throw e;
            }
        }

        /// <summary>
        /// determines what subscription environment is being used for creating subscriptions with credit cards
        /// </summary>
        /// <param name="e"></param>
        /// <returns></returns>
        private bool isProductionSubscriptionEnvironement(SeleniumServer.OrderAppEnvironment e) {
            if (e == SeleniumServer.OrderAppEnvironment.Prod || e == SeleniumServer.OrderAppEnvironment.Beta) {
                return true;
            }
            if (e == SeleniumServer.OrderAppEnvironment.Int || e == SeleniumServer.OrderAppEnvironment.Load || e == SeleniumServer.OrderAppEnvironment.Local || e == SeleniumServer.OrderAppEnvironment.Test) {
                return false;
            }
            //may want to throw error for debugging use
            return false;
        }


        /// <summary>
        /// writes text to temporary buffer
        /// </summary>
        /// <param name="lb"></param>
        /// <param name="s"></param>
        public void logLine(ref LogBuffer lb, String s) {
            lb.TextLog += s + Environment.NewLine;
        }

        /// <summary>
        /// Writes all text from logBuffer to file
        /// </summary>
        /// <param name="lb"></param>
        public void logLine(LogBuffer lb) {
            if (lb.TextLog.Length == 0) {
                return;
            }
            try {
                logFile.WriteLine(lb.TextLog);
            } catch (Exception e) {
                Console.WriteLine(e.Message);
            }
        }


        /// <summary>
        /// Writes string directly and immediately to log file
        /// </summary>
        /// <param name="lb"></param>
        public void logLine(String s) {
            try {
                logFile.WriteLine(s);
            } catch (Exception e) {
                Console.WriteLine(e.Message);
            }
        }


        private void tearDownTestCase(bool blankPage, bool clearCookies, bool refresh) {
            if ( blankPage ) {
                sel.openBlankPage( browser );
            } else {
                if (clearCookies) {
                    sel.DeleteAllVisibleCookies();
                }
                if (refresh) {
                    sel.Refresh();//refresh and cookie clear on session stored pages currently will open the /null path which goes to default offer 
                }
            }
        }


        /*
        private void tearDownTest() {
            try {
                //could be a js alert box which js has no way to close. If run locally using XP, 
                //c# could access it through windows API to focus on the alert of the browser process, but would fail in all other cases
                sel.Close();
            } catch (Exception e) {
                sel.Stop();
            }
        }*/

        private void tearDownServerAndLogging() {
            try {
                sel.Close();
            } catch (Exception e) {
                Console.WriteLine(e.Message);
            } finally {
                sel.Stop();
                //sel.ShutDownSeleniumServer(); done via the singleton process when it terminates
            }

            try {
                logFile.Flush();
                logFile.Close();
            } catch (Exception e) {
                Console.WriteLine(e.Message);
                return;
            } finally {
                logFile.Dispose();
            }

        }


        /// <summary>
        /// Sets a list of URLs to the expected environment for use during the test.
        /// These URIs are either full or the base URI specific to particular environments.
        /// These should only be created for inconsistent URL naming, and then only for the
        /// parts that are inconsistent. The fewer of these cluttering things the better.
        /// 
        /// </summary>
        /// <param name="environment"></param>
        private void buildEnvironmentSpecificURIs(SeleniumServer.OrderAppEnvironment environment) {
            /*
             * examples:
             * 
             * local
             * sIn: http://127.0.0.1:8080/signup-web/premier/monthly/14d
             * sessExp: http://127.0.0.1:8080/signup-web/cs/SessionExpired
             * payflow: https://payflow.int.real.com/payflow?t=
             * trialExp: http://127.0.0.1:8080/signup-web/premier/monthly/14d/?_f
             * 
             */
            switch (environment) {
                case SeleniumServer.OrderAppEnvironment.Local://2.0 currently
                orderURI               = new Uri(@"http://127.0.0.1:8080/signup-web/",UriKind.Absolute);
                orderMarketingURI      = new Uri(@"http://127.0.0.1:8080/signup-web/realstore/tadmin", UriKind.Absolute);
                payflowURI             = new Uri(@"https://payflow.int.real.com/payflow", UriKind.Absolute);
                mp3StoreURI            = new Uri(@"http://mp3.int.rhapsody.com/", UriKind.Absolute);
                rotwSigninFullURI      = new Uri(@"https://secure-rhapcom-int.internal.rhapsody.com/authentication/login", UriKind.Absolute);
                rotwURI                = new Uri(@"http://rhapcom-int.internal.rhapsody.com", UriKind.Absolute);
                mp3SigninFullURI       = new Uri(@"https://secure.mp3.int.rhapsody.com/signin.html", UriKind.Absolute);
                mp3PurchaseFlowFullURI = new Uri(@"https://realstore.int.rhapsody.com/rhapsody/mp3store", UriKind.Absolute);
                sessExpireFullURI      = new Uri(@"http://127.0.0.1:8080/signup-web/cs/SessionExpired", UriKind.Absolute);
                break;
                case SeleniumServer.OrderAppEnvironment.Int://1.0 currently
                orderURI               = new Uri(@"https://order-int.internal.rhapsody.com/", UriKind.Absolute);
                orderMarketingURI      = new Uri(@"https://order-int.internal.rhapsody.com/tadmin/marketing", UriKind.Absolute);            
                payflowURI             = new Uri(@"https://payment-int.internal.rhapsody.com/payflow", UriKind.Absolute);
                mp3StoreURI            = new Uri(@"http://mp3.int.rhapsody.com/", UriKind.Absolute);
                rotwSigninFullURI      = new Uri(@"https://secure-rhapcom-int.internal.rhapsody.com/authentication/login", UriKind.Absolute);
                rotwURI                = new Uri(@"http://rhapcom-int.internal.rhapsody.com", UriKind.Absolute);
                mp3SigninFullURI       = new Uri(@"https://secure.mp3.int.rhapsody.com/signin.html", UriKind.Absolute);
                mp3PurchaseFlowFullURI = new Uri(@"https://realstore.int.rhapsody.com/rhapsody/mp3store", UriKind.Absolute);
                sessExpireFullURI      = new Uri(@"http://www.rhapsody.com/-expired", UriKind.Absolute);
                break;
                case SeleniumServer.OrderAppEnvironment.Load://1.0 currently
                orderURI               = new Uri(@"https://order-load.internal.rhapsody.com/", UriKind.Absolute);
                orderMarketingURI      = new Uri(@"https://order-load.internal.rhapsody.com/tadmin/marketing", UriKind.Absolute);            
                payflowURI             = new Uri(@"https://payment-int.internal.rhapsody.com/payflow", UriKind.Absolute);//https://payment-int.internal.rhapsody.com/payflow/?t=E
                mp3StoreURI =            new Uri(@"http://mp3.int.rhapsody.com/", UriKind.Absolute);
                rotwSigninFullURI      = new Uri(@"https://secure-rhapcom-int.internal.rhapsody.com/authentication/login", UriKind.Absolute);
                rotwURI                = new Uri(@"http://rhapcom-int.internal.rhapsody.com", UriKind.Absolute);
                mp3SigninFullURI =       new Uri(@"https://secure.mp3.int.rhapsody.com/signin.html", UriKind.Absolute);
                mp3PurchaseFlowFullURI = new Uri(@"https://realstore.int.rhapsody.com/rhapsody/mp3store", UriKind.Absolute);
                sessExpireFullURI =      new Uri(@"http://www.rhapsody.com/-expired", UriKind.Absolute);
                break;
                case SeleniumServer.OrderAppEnvironment.Test://1.0 currently
                orderURI =               new Uri(@"https://order-test.internal.rhapsody.com/", UriKind.Absolute);
                orderMarketingURI      = new Uri(@"https://order-test.internal.rhapsody.com/tadmin/marketing", UriKind.Absolute);            
                payflowURI =             new Uri(@"https://payment-int.internal.rhapsody.com/payflow", UriKind.Absolute);
                mp3StoreURI =            new Uri(@"http://mp3.int.rhapsody.com/", UriKind.Absolute);
                rotwSigninFullURI      = new Uri(@"https://secure-rhapcom-int.internal.rhapsody.com/authentication/login", UriKind.Absolute);
                rotwURI                = new Uri(@"http://rhapcom-int.internal.rhapsody.com", UriKind.Absolute);
                mp3SigninFullURI =       new Uri(@"https://secure.mp3.int.rhapsody.com/signin.html", UriKind.Absolute);
                mp3PurchaseFlowFullURI = new Uri(@"https://realstore.int.rhapsody.com/rhapsody/mp3store", UriKind.Absolute);
                sessExpireFullURI =      new Uri(@"http://www.rhapsody.com/-expired", UriKind.Absolute);
                break;
                case SeleniumServer.OrderAppEnvironment.Beta://1.0 currently
                orderURI =               new Uri(@"https://order-beta.rhapsody.com/", UriKind.Absolute);
                orderMarketingURI      = new Uri(@"http://order-int-1203.sea2.rhapsody.com:8080/order/tadmin", UriKind.Absolute);            
                payflowURI =             new Uri(@"https://payment.rhapsody.com/payflow", UriKind.Absolute);
                mp3StoreURI =            new Uri(@"http://mp3.int.rhapsody.com/", UriKind.Absolute);
                rotwSigninFullURI =      new Uri(@"https://secure-www.rhapsody.com/authentication/login", UriKind.Absolute);
                rotwURI =                new Uri(@"http://www.rhapsody.com/", UriKind.Absolute);
                mp3SigninFullURI =       new Uri(@"https://secure.mp3.int.rhapsody.com/signin.html", UriKind.Absolute);
                mp3PurchaseFlowFullURI = new Uri(@"https://realstore.int.rhapsody.com/rhapsody/mp3store", UriKind.Absolute);
                sessExpireFullURI =      new Uri(@"http://www.rhapsody.com/-expired", UriKind.Absolute);
                break;
                case SeleniumServer.OrderAppEnvironment.Prod:

                break;
            }
        }
        #endregion



    }




    #region structs


    /// <summary>
    /// This stores the expected selectors and url for a given pageType
    /// </summary>
    public struct OrderPathPage {
        public TestRunner.OrderPageTypes PageType { get; private set; }
        public Uri StaticURL { get; private set; }//for urls that change based on orderpath(as opposed to say payflow page) this has to be used in conjunction with orderpath.url
        public List<TestRunner.DifferedComparisonDelegate> Rules { get; set; }
        public List<String[][]> RuleValues { get; set; }

        //starting them all as empty arrays so logic doesn't have to worry about them being null
        public OrderPathPage(Uri url, TestRunner.OrderPageTypes type): this() {
            StaticURL = url;
            PageType = type;
            Rules = new List<TestRunner.DifferedComparisonDelegate>();
            RuleValues = new List<string[][]>();
        }
    }




    /// <summary>
    /// This stores all the data gathered from the tadmin/marketing page for all the Orderpaths
    /// </summary>
    public struct OrderPath {
        public String CategoryTab { get; set; }
        public String Name { get;  set; }
        public String URL { get;  set; }
        public bool Trial { get;  set; }
        public bool Active { get;  set; }
        public TestRunner.OrderPathSkin Skin { get;  set; }
        public TestRunner.OrderPathFlow Flow { get; set; }
        public bool Post { get; set; }
        public bool SignUpOverlay { get; set; }

        public bool isCouponPath() {
            return this.Skin == TestRunner.OrderPathSkin.RhapMP3CouponsSkin || 
                this.Skin == TestRunner.OrderPathSkin.RhapPrepaidDownloadSkin ||
                this.Skin == TestRunner.OrderPathSkin.RhapRewardsSkin || 
                this.Skin == TestRunner.OrderPathSkin.RhapPrepaidSubscriptionSkin ||
                this.Skin == TestRunner.OrderPathSkin.rhapCostcoRewardsSkin ||
                this.Skin == TestRunner.OrderPathSkin.rhapCostcoMP3CouponSkin;
        }
    }

    /// <summary>
    /// Holds all logging(txt and xls) created during the course of executing all tests for a single path
    /// </summary>
    public struct LogBuffer {
        //text log buffer data
        public String TextLog { get; set; }
        
        //excel log buffer data
        //Reference objects initialize to null, and no parameterless constructors allowed for structs so fuck it, we'll do it live
        private LinkedList<OrderPath> orderpaths;
        public LinkedList<OrderPath> Orderpaths { 
            get{
                if (orderpaths == null) {
                    orderpaths = new LinkedList<OrderPath>();
                }
                return orderpaths;
            }
            private set {
                orderpaths = value;
            }
        }
        public LinkedList<String> testNames;
        public LinkedList<String> TestNames {
            get{
                if (testNames == null) {
                    testNames = new LinkedList<String>();
                }
                return testNames;
            }
            private set {
                testNames = value;
            }
        }
        private LinkedList<bool> successes;
        public LinkedList<bool> Successes {
            get {
                if (successes == null) {
                    successes = new LinkedList<bool>();
                }
                return successes;
            }
            private set {
                successes = value;
            }
        }

        

    }

    /// <summary>
    /// Used for testing the links in the account creation page
    /// </summary>
    public struct PopupLink {
        public String Locator { get; set; }
        public String DomLinksName { get; set; }
        public String WindowJSID { get; set; }
        public String WindowTitle { get; set; }
        public bool inClient {
            get {
                return Locator.Contains("inclientPopupNav");
                //inclientPopupNav
            }
        }

        public PopupLink(String loc, String linksName, String windowID, String title) : this(){
            //all possible dom values in Links.AlwaysOpenInWindow "PrivacyPolicy", "TermsOfUse", "OfferTerms", "OurGuarantee", "CustomerSupport" , "SystemRequirements"
            //all window IDs "privacy_policy_rhap", "terms_of_use_rhap", "our_guarantee", ""(and title is "Offer Terms", this is relevent because selenium has weird select by title/window ID inconsistencies), "customer_support", "system_requirements_rhap"
            // "customer_support_vcast" "terms_of_use_vcast" "privacy_policy_vcast"
            Locator = loc;
            DomLinksName = linksName;
            WindowJSID = windowID;
            WindowTitle = title;
        }

    }
    #endregion


}
